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

Ste*_*ven 48 .net c# asp.net-core-mvc asp.net-core

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

这是我现在的代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:如何在ASP.NET Core MVC中读取action方法的属性?

Hen*_*ema 61

您可以MethodInfo通过ControllerActionDescriptor课程访问该操作:

public void OnActionExecuting(ActionExecutingContext context)
{
    var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
    if (controllerActionDescriptor != null)
    {
        var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这是关于 MVC 6(或 Core 1.0)。 (3认同)
  • 检查 controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes() 以获取已在控制器而不是方法上设置的属性也很有用。 (2认同)
  • 您可以对此代码使用模式匹配:`if (context.ActionDescriptor is ControllerActionDescriptorcontrollerActionDescriptor)` (2认同)

Joa*_*oas 23

调用GetCustomAttributes方法和/或类很(呃)。你应该不会调用GetCustomAttributes,因为.NET 2.2的核心,这@Henk默勒马是在暗示每个请求。(有一个例外,我稍后会解释)

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

然后,您可以通过访问您的asp.net的核心过滤器这些元数据EndpointMetadata属性的的ActionDescriptor

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)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您无权访问来自 asp.net core 3.0ActionDescriptor(例如:因为您从中间件而不是过滤器操作)您可以使用GetEndpoint扩展方法访问它的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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 如果您将端点路由与 ASP.NET Core 3.0 或更高版本一起使用,这应该是正确的答案 (4认同)

Axe*_*uez 6

我创建了一个扩展方法,模仿GetCustomAttributesHenk Mollema解决方案中的原始方法.

    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>();
    }
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你.


Mic*_*Mao 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;
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)