You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET Core 3中获取路由属性?升级至Preview7后自定义属性获取失败

解决.NET Core 3.0+中从Endpoint获取授权自定义属性的问题

升级到.NET Core 3.0 Preview 7后,授权流程里的context.Resource类型从AuthorizationFilterContext变成了Microsoft.AspNetCore.Http.Endpoint,这是因为ASP.NET Core 3.0开始采用端点路由(Endpoint Routing)作为默认方案,授权系统也同步适配了这个变化。不过我们可以通过Endpoint的元数据集合,重新拿到控制器/Action上的自定义属性,下面是具体的解决方法:

修改后的核心逻辑

在你的HandleRequirementAsync方法中,处理Endpoint类型的资源时,通过endpoint.Metadata.GetMetadata<ControllerActionDescriptor>()拿到对应的Action描述器,之后就能像之前版本一样获取方法(或控制器)上的自定义属性了:

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
    var attributes = new List<TAttribute>();

    // 处理.NET Core 3.0+的Endpoint类型资源
    if (context.Resource is Microsoft.AspNetCore.Http.Endpoint endpoint)
    {
        var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
        if (actionDescriptor != null)
        {
            // 添加Action方法上的自定义属性
            attributes.AddRange(GetAttributes(actionDescriptor.MethodInfo));
            // 可选:如果你的自定义属性可能放在控制器类上,加上这一行
            attributes.AddRange(GetAttributes(actionDescriptor.ControllerTypeInfo));
        }
    }
    // 兼容旧版本的AuthorizationFilterContext(可选,若需兼容混合路由模式)
    else if (context.Resource is AuthorizationFilterContext filterContext)
    {
        var action = filterContext.ActionDescriptor as ControllerActionDescriptor;
        if (action != null)
        {
            attributes.AddRange(GetAttributes(action.MethodInfo));
            attributes.AddRange(GetAttributes(action.ControllerTypeInfo));
        }
    }

    return HandleRequirementAsync(context, requirement, attributes);
}

完整的修改后代码

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Gamma.Core.Security
{
    public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement>
        where TRequirement : IAuthorizationRequirement
        where TAttribute : Attribute
    {
        private readonly Microsoft.AspNetCore.Http.IHttpContextAccessor _httpContextAccessor;

        public AttributeAuthorizationHandler(Microsoft.AspNetCore.Http.IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
        {
            var attributes = new List<TAttribute>();

            // 处理.NET Core 3.0+的Endpoint资源
            if (context.Resource is Microsoft.AspNetCore.Http.Endpoint endpoint)
            {
                var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
                if (actionDescriptor != null)
                {
                    attributes.AddRange(GetAttributes(actionDescriptor.MethodInfo));
                    // 可选:添加控制器类上的自定义属性
                    attributes.AddRange(GetAttributes(actionDescriptor.ControllerTypeInfo));
                }
            }
            // 兼容旧版本的AuthorizationFilterContext
            else if (context.Resource is AuthorizationFilterContext filterContext)
            {
                var action = filterContext.ActionDescriptor as ControllerActionDescriptor;
                if (action != null)
                {
                    attributes.AddRange(GetAttributes(action.MethodInfo));
                    attributes.AddRange(GetAttributes(action.ControllerTypeInfo));
                }
            }

            return HandleRequirementAsync(context, requirement, attributes);
        }

        protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);

        private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
        {
            return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
        }
    }
}

关键说明

  • Endpoint.Metadata是存储当前端点所有关联元数据的集合,其中包含的ControllerActionDescriptor保存了控制器和Action的完整信息,这是我们获取自定义属性的关键入口。
  • 如果你的自定义属性不仅会标记在Action方法上,还可能标记在控制器类上,记得保留actionDescriptor.ControllerTypeInfo的处理逻辑。
  • 保留旧版本的AuthorizationFilterContext判断,可以让代码在混合路由模式下(比如部分路由未迁移到端点路由)依然正常工作,若不需要兼容可直接移除这部分代码。

内容的提问来源于stack exchange,提问作者Bahman Shafiei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:35:50