簡體   English   中英

如何在ActionExecutingContext中訪問ActionDescriptor的MethodInfo.ReturnType?

[英]How can I access the MethodInfo.ReturnType for an ActionDescriptor within the ActionExecutingContext?

我的應用程序上有一個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對象中提取該值,並創建一個支持方法來返回一個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;
    }

只要控制器中的操作名稱是唯一的,分配returnType就可以在try-block中工作。 但是如果控制器中存在多個相同操作名稱的實例,則會發生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 { });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM