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

Posted

技术标签:

【中文标题】如何在 ASP.NET Core MVC 中读取操作方法的属性?【英文标题】:How to read action method's attributes in ASP.NET Core MVC? 【发布时间】:2015-08-07 09:47:53 【问题描述】:

基于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 中读取 action 方法的属性?

【问题讨论】:

你会得到MemberInfo,不管你有兴趣使用反射API,然后使用GetCustomAttributes。希望我没有误解这个问题 【参考方案1】:

您可以通过ControllerActionDescriptor类访问动作的MethodInfo

public void OnActionExecuting(ActionExecutingContext context)

    if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
    
        var actionAttributes = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true);
    

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

【讨论】:

如何在 asp.net mvc 6 中做到这一点 这是关于 MVC 6(或 Core 1.0)的。 我的错我没看清楚。你能检查我的答案是否正确吗?我只是找到一种获取属性的方法并将其发布。 检查 controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes() 以获取已在控制器上设置的属性而不是方法也很有用。 您可以对此代码使用模式匹配:if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)【参考方案2】:

在方法和/或类上调用GetCustomAttributes(呃)。自 .net core 2.2 以来,您应该调用GetCustomAttributes 的每个请求,@Henk Mollema 建议这样做。 (有一个例外,我稍后会解释)

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

然后您可以通过ActionDescriptor class 的EndpointMetadata property 在您的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,您可以使用 GetEndpoint extension method访问它是Metadata。 有关更多信息,请参阅this 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 core 中几乎从来没有。

【讨论】:

如果您在 ASP.NET Core 3.0 或更高版本中使用端点路由,这应该是正确答案 很好的答案,我不得不升级到 3.1,但这是值得的。【参考方案3】:

我的自定义属性继承自 ActionFilterAttribute。我把它放在我的控制器上,但有一个动作不需要它。我想使用AllowAnonymous 属性来忽略它,但它不起作用。所以我在我的自定义属性中添加了这个 sn-p 以找到 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;
                
            
        
    

【讨论】:

FilterDescriptors 属性仅在您的自定义属性实际上是 MVC Filter 时才有效。如果您将自定义 passive attribute 应用于您的操作,那么显然您的解决方案将不起作用。【参考方案4】:

我基于 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>();
    

希望对你有帮助。

【讨论】:

与 NuGet 包 System.Reflection.Extensions 和使用到 System.Reflection 结合使用效果很好【参考方案5】:

正如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()

【讨论】:

以上是关于如何在 ASP.NET Core MVC 中读取操作方法的属性?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 asp net core 2.2 中间件中多次读取请求正文?

菜鸟入门ASP.NET Core5:命令行配置Json文件配置Bind读取配置到C#实例在Core Mvc中使用Options

读取解决方案数据文件 ASP.Net Core

如何解决 docker-compose 环境变量不起作用 ASP.Net Core MVC

asp.net mvc5 如何控制没有权限的页面不显示

如何在 ASP.NET Core 5 MVC (.NET 5) 中获取记录的用户数据?