c# - 如何访问 ActionExecutingContext 中 ActionDescriptor 的 MethodInfo.ReturnType?

标签 c# asp.net .net asp.net-mvc

我的应用程序上有一个 ActionFilterAttribute,用于在检测到用户未通过身份验证时重定向用户。在过滤器中,我想检测操作的 ReturnType 何时为 JsonResult。

作为解决方法,我最初创建了 IsJsonResult 的自定义属性,并使用该属性修饰了我的解决方案中的 JsonResult 方法。这有效,并在操作过滤器中实现如下:

public class CheckUser : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext actionExecutingContext)
    {
        base.OnActionExecuting(actionExecutingContext);
        object[] customAttributes = actionExecutingContext.ActionDescriptor.GetCustomAttributes(true);
        bool isJsonResult = customAttributes.FirstOrDefault(a => a.GetType() == typeof(IsJsonResult)) != null;

        if (isJsonResult)
        {
            return; // Don't perform any additional checks on JsonResult requests.
        }

        // Additional checking code omitted.
    }
}

这行得通,但我不喜欢装饰该项目中所有 JsonResult 操作的想法。如果一个新的 JsonResult 被添加到项目中,这很容易失败,而我们忘记相应地装饰它。

此外,我可以看到名称为“JsonResult”的 ReturnType 位于上面所示的 actionExecutingContext 对象内的调试器中。这是监 window 口中显示的路径:

actionExecutingContext > ActionDescriptor > [System.Web.Mvc.ReflectedActionDescriptor] > MethodInfo > ReturnType > FullName

该 FullName 属性的值为“System.Web.Mvc.JsonResult”。

所以我似乎可以直接从 actionExecutingContext 对象中提取该值,并创建一个支持方法来返回 bool 指示符。为此,我编写了以下代码。

    private bool isReturnTypeJson(ActionExecutingContext actionExecutingContext)
    {
        string actionName = actionExecutingContext.ActionDescriptor.ActionName;
        string controllerName = actionExecutingContext.ActionDescriptor.ControllerDescriptor.ControllerName;
        Type controllerType = actionExecutingContext.Controller.GetType();
        try
        {
            // Only effective when the actionName is not duplicated in the controller.
            Type returnType = controllerType.GetMethod(actionName).ReturnType;
            return (returnType.Name == "JsonResult");
        }
        catch (AmbiguousMatchException)
        {
            // Using LINQ, can I filter this collection to isolate just the methods
            // that have the same name as the "actionName" variable above?
            MethodInfo[] methodsInfoCollection = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance);

            // Attempted code from https://stackoverflow.com/questions/15283158/net-mvc-counting-action-methods-in-web-application
            //var info = typeof(controllerType)
            //        .Assembly.GetTypes()
            //        .Where(t => typeof(Controller).IsAssignableFrom(t))
            //        .Where(t => t.Namespace.StartsWith("AwesomeProduct.Web"))
            //        .SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Instance))
            //        .Where(m => typeof(ActionResult).IsAssignableFrom(m.ReturnType))
            //        .Where(m => !m.IsAbstract)
            //        .Where(m => m.GetCustomAttribute<NonActionAttribute>() == null);

        }
        return false;
    }

只要 Action 名称在 Controller 中是唯一的,就可以在 try block 中分配 returnType。但是如果 Controller 中有多个相同 Action 名称的实例,则会发生 AmbiguousMatchException。因此,在 catch block 中,我已将方法分配给一个集合。 使用 LINQ,我如何过滤来自 methodsInfoCollection 变量的值到通过 ActionExecutingContext 到达的操作?

下面是我研究过的一些文章,并使用了其中的一些想法。但我还没有弄清楚。

感谢您的帮助。

==============

更新到原始代码。这可行,但循环并不理想。

private bool isReturnTypeJson(ActionExecutingContext actionExecutingContext)
{
    string actionName = actionExecutingContext.ActionDescriptor.ActionName;
    string controllerName = actionExecutingContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    Type controllerType = actionExecutingContext.Controller.GetType();
    try
    {
        // Only effective when the actionName is not duplicated in the controller.
        Type returnType = controllerType.GetMethod(actionName).ReturnType;
        return (returnType.Name == "JsonResult");
    }
    catch (AmbiguousMatchException)
    {
        // Using LINQ, can I filter this collection to isolate just the methods with a name of actionName.
        MethodInfo[] methodInfoCollection = controllerType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
        foreach (MethodInfo methodInfo in methodInfoCollection)
        {
            if (methodInfo.ReturnType != null) {
                if (methodInfo.ReturnType == typeof(ActionResult))
                {
                    return false;
                }
                if (methodInfo.ReturnType == typeof(JsonResult))
                {
                    return true;
                }
            }
        }
    }
    return false;
}

请参阅下面 Reza Aghaei 的解决方案。他的解决方案完全消除了对单独方法的需求。

最佳答案

你可以使用

((ReflectedActionDescriptor)filterContext.ActionDescriptor).MethodInfo.ReturnType 

这是我试图检查返回类型是否为 JsonResult 的内容:

((ReflectedActionDescriptor)filterContext.ActionDescriptor).MethodInfo.ReturnType == typeof(JsonResult)

它为我的操作返回 true:

public JsonResult Index()
{
    return Json(new { });
}

关于c# - 如何访问 ActionExecutingContext 中 ActionDescriptor 的 MethodInfo.ReturnType?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33089280/

相关文章:

c# - 将 HTTP 音频流记录到文件

c# - 当前监视器的分辨率

c# - 当线程不活动时释放资源

javascript - 如何向用户控件添加 expando 属性?

c# - 如何从*代码隐藏*强制 IE 9 进入 IE8 兼容模式

c# - Control.UniqueId 是什么时候创建的?

c# 从 System.Data.DataRowView 转换为字符串

c# - 试图回避单例/上帝/经理类。不过不确定我应该如何维持功能

.net - 如何强制在 Visual Studio 2013 中打开解决方案文件 (SLN)?

java - Bluestacks Android 模拟器是使用 .Net 构建的?