如何在ASP.NET Core MVC中读取动作方法的属性?

时间:2015-08-07 09:47:53

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

基于this article我试图为ASP.NET Core创建一个IActionFilter实现,它可以处理控制器上标记的属性和控制器的操作。虽然读取控制器的属性很容易,但我无法找到一种方法来读取操作方法中定义的属性。

这是我现在的代码:

public sealed class ActionFilterDispatcher : IActionFilter
{
    private readonly Func<Type, IEnumerable> container;

    public ActionFilterDispatcher(Func<Type, IEnumerable> container)
    {
        this.container = container;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        var attributes = context.Controller.GetType().GetCustomAttributes(true);

        attributes = attributes.Append(/* how to read attributes from action method? */);

        foreach (var attribute in attributes)
        {
            Type filterType = typeof(IActionFilter<>).MakeGenericType(attribute.GetType());
            IEnumerable filters = this.container.Invoke(filterType);

            foreach (dynamic actionFilter in filters)
            {
                actionFilter.OnActionExecuting((dynamic)attribute, context);
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        throw new NotImplementedException();
    }
}

我的问题是:如何阅读ASP.NET Core MVC中的操作方法属性?

5 个答案:

答案 0 :(得分:55)

您可以通过ControllerActionDescriptor课程

访问操作的MethodInfo
public void OnActionExecuting(ActionExecutingContext context)
{
    var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
    if (controllerActionDescriptor != null)
    {
        var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
    }
}

MVC 5 ActionDescriptor类用于实现允许访问属性的ICustomAttributeProvider接口。出于某种原因,这已在ASP.NET Core MVC ActionDescriptor类中删除。

答案 1 :(得分:11)

在方法和/或类上调用GetCustomAttributes的操作。自.net core 2.2(@Henk Mollema建议)以来,您不应调用每个GetCustomAttributes请求。 (有一个例外情况,我将在后面解释)

相反,在应用程序启动时,asp.net核心框架将为您在操作方法和控制器上调用GetCustomAttributes并将结果存储在EndPoint metadata中。

然后您可以通过EndpointMetadata property中的ActionDescriptor class在asp.net核心过滤器中访问此元数据。

public class CustomFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Get attributes on the executing action method and it's defining controller class
        var attributes = context.ActionDescriptor.EndpointMetadata.OfType<MyCustomAttribute>();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
    }
}

如果您无权访问ActionDescriptor(例如:因为您是通过中间件而不是过滤器操作的),则来自asp.net core 3.0 ,您可以使用{ {3}}来访问它的GetEndpoint extension method。 有关更多信息,请参见Metadata github问题。

public class CustomMiddleware
{
    private readonly RequestDelegate next;

    public CustomMiddleware(RequestDelegate next)
    {
        this.next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // Get the enpoint which is executing (asp.net core 3.0 only)
        var executingEnpoint = context.GetEndpoint();

        // Get attributes on the executing action method and it's defining controller class
        var attributes = executingEnpoint.Metadata.OfType<MyCustomAttribute>();

        await next(context);

        // Get the enpoint which was executed (asp.net core 2.2 possible after call to await next(context))
        var executingEnpoint2 = context.GetEndpoint();

        // Get attributes on the executing action method and it's defining controller class
        var attributes2 = executingEnpoint.Metadata.OfType<MyCustomAttribute>();
    }
}

类似于上面所述,端点元数据包含操作方法及其定义的控制器类的属性。这意味着,如果您想显式忽略应用于控制器类或操作方法的属性,则必须使用GetCustomAttributes。在asp.net核心中几乎从来没有这种情况。

答案 2 :(得分:6)

我根据Henk Mollema的解决方案创建了一个模仿原始GetCustomAttributes的扩展方法。

    public static IEnumerable<T> GetCustomAttributes<T>(this Microsoft.AspNet.Mvc.Abstractions.ActionDescriptor actionDescriptor) where T : Attribute
    {
        var controllerActionDescriptor = actionDescriptor as ControllerActionDescriptor;
        if (controllerActionDescriptor != null)
        {
            return controllerActionDescriptor.MethodInfo.GetCustomAttributes<T>();
        }

        return Enumerable.Empty<T>();
    }

希望它有所帮助。

答案 3 :(得分:5)

我的自定义属性是从ActionFilterAttribute继承的。我把它放在我的控制器上,但有一个动作不需要它。我想使用AllowAnonymous属性忽略它,但它不起作用。因此,我在自定义属性中添加此代码段以查找AllowAnonymous并跳过它。你可以在for循环中获得其他内容。

    public class PermissionAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            foreach (var filterDescriptors in context.ActionDescriptor.FilterDescriptors)
            {
                if (filterDescriptors.Filter.GetType() == typeof(AllowAnonymousFilter))
                {
                    return;
                }
            }
        }
    }

答案 4 :(得分:0)

Henk Mollena回答

public void OnActionExecuting(ActionExecutingContext context) { var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; if (controllerActionDescriptor != null) { var controllerAttributes = controllerActionDescriptor .MethodInfo .GetCustomAttributes(inherit: true); } }

如果要检查应用于操作的属性的存在,

是正确的方法。

如果您想检查是否存在应用于控制器的属性

,我只是想添加到他的答案中
public void OnActionExecuting(ActionExecutingContext context)
{
    var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
    if (controllerActionDescriptor != null)
    {
        var actionAttributes = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(inherit: true);
    }
}

您还可以使用GetCustomAttributes函数的重载函数来获取您的特定属性

var specificAttribute = GetCustomAttributes(typeof(YourSpecificAttribute), true).FirstOrDefault()