【问题标题】:How to read action method's attributes in ASP.NET Core MVC?如何在 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。希望我没有误解这个问题

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


【解决方案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 classEndpointMetadata 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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多