2015-10-12 23 views
4

我的應用程序中有一個ActionFilterAttribute,用於在檢測到用戶未通過身份驗證時重定向用戶。在過濾器中,我想檢測動作的ReturnType何時是JsonResult。如何在ActionExecutingContext中訪問ActionDescriptor的MethodInfo.ReturnType?

作爲一種解決方法,我最初創建了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; 
    } 

只要操作名稱在控制器中唯一,就可以在try-block中分配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解決方案。他的解決方案完全消除了對單獨方法的需求。

+0

謝謝@Reza Aghaei。 filterContext.Result.GetType()== typeof(JsonResult);返回一個NullReferenceException。 Result對象爲null。你會認爲這將是人口稠密的,這是最直觀的方法。 –

+0

是的,我檢查後,我刪除了我的評論;) –

+0

我真的很感謝你的幫助。我更新了方法來循環收集。這是可行的,但並不理想。請參閱原始帖子中的調整。 –

回答

5

您可以使用

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

這裏就是我想檢查是否返回類型爲JsonResult

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

,並返回我的行動真:

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

酷!讓我給一個鏡頭。 –

+0

這就像一個冠軍!謝謝。 –

+0

歡迎您:) –

相關問題