【问题标题】:How can I access the MethodInfo.ReturnType for an ActionDescriptor within the ActionExecutingContext?如何访问 ActionExecutingContext 中 ActionDescriptor 的 MethodInfo.ReturnType?
【发布时间】:2016-01-10 09:55:36
【问题描述】:

我的应用程序上有一个 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 对象内的调试器中。这是监视窗口中显示的路径:

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

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

所以看起来我可以直接从 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
            // 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;
    }

只要动作名称在控制器中是唯一的,就可以在 try 块中分配 returnType。但如果控制器中有多个相同动作名称的实例,则会发生 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 的解决方案。他的解决方案完全不需要单独的方法。

【问题讨论】:

  • 感谢@Reza Aghaei。 filterContext.Result.GetType() == typeof(JsonResult);返回 NullReferenceException。结果对象为空。你会认为它会被填充,这是最直观的方法。
  • 是的,在我检查后我删除了我的评论;)
  • 非常感谢您的帮助。我已经更新了循环遍历集合的方法。这是可行的,但并不理想。请参阅原始帖子中的调整。

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


【解决方案1】:

你可以使用

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

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

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

它为我的操作返回 true:

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

【讨论】:

  • 酷!让我试一试。
  • 对于 .Net Dore - 使用 ControllerActionDescriptor 而不是 ReflectedActionDescriptor
猜你喜欢
  • 1970-01-01
  • 2012-10-25
  • 2021-06-20
  • 1970-01-01
  • 1970-01-01
  • 2016-08-06
  • 1970-01-01
  • 2019-10-06
  • 2012-10-21
相关资源
最近更新 更多