我的应用程序上有一个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添加到项目中,那很容易失败,我们忘记相应地修饰它。
此外,我可以看到ReturnType的名称为" JsonResult"是在上面显示的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的解决方案。他的解决方案完全消除了对单独方法的需求。
答案 0 :(得分:12)
您可以使用
((ReflectedActionDescriptor)filterContext.ActionDescriptor).MethodInfo.ReturnType
以下是我尝试检查返回类型是否为JsonResult
:
((ReflectedActionDescriptor)filterContext.ActionDescriptor).MethodInfo.ReturnType == typeof(JsonResult)
对于我的行动,它返回true:
public JsonResult Index()
{
return Json(new { });
}