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

.NET Core中自定义Attribute的依赖注入实现方法咨询

在.NET Core自定义Attribute中实现依赖注入的解决方案

首先得明确一个核心问题:.NET 里的 Attribute 实例是由 CLR 直接创建的,根本不走依赖注入容器的实例化流程。所以你想在 Attribute 的构造函数里直接注入 IConfiguration 这类服务是行不通的——CLR 根本不知道你的 DI 容器存在,自然没法帮你自动解析这些依赖参数。

针对你这个自定义路由Attribute的场景(实现了IRouteTemplateProvider),最贴合ASP.NET Core设计的解决方案是用**自定义路由约定(Route Convention)**来实现,下面是具体步骤:

步骤1:简化你的CustomRouteAttribute,只做标记用

把原来带DI参数的构造函数去掉,让Attribute仅作为标识,不需要承载业务逻辑:

public class CustomRouteAttribute : Attribute
{
    // 保留你需要的路由属性,比如Order和Name
    public int? Order { get; set; }
    public string Name { get; set; }
}

步骤2:创建自定义路由约定类,注入依赖处理逻辑

路由约定是ASP.NET Core官方提供的扩展路由规则的方式,这类类会由DI容器管理,所以可以正常注入IConfiguration:

using Microsoft.AspNetCore.Mvc.ApplicationModels;

public class CustomRouteConvention : IApplicationModelConvention
{
    private readonly string _serverKey;

    // 这里直接注入IConfiguration,完全没问题
    public CustomRouteConvention(IConfiguration configuration)
    {
        _serverKey = configuration.GetSection("serverkey").Value ?? string.Empty;
    }

    public void Apply(ApplicationModel application)
    {
        // 遍历所有控制器,找到带有CustomRouteAttribute的目标
        foreach (var controller in application.Controllers)
        {
            var customRouteAttr = controller.Attributes.OfType<CustomRouteAttribute>().FirstOrDefault();
            if (customRouteAttr == null)
                continue;

            // 拼接你的自定义路由模板
            var routeTemplate = $"api/{_serverKey}/{controller.ControllerName}";
            
            // 给控制器添加这个自定义路由
            controller.Selectors.Add(new SelectorModel
            {
                AttributeRouteModel = new AttributeRouteModel
                {
                    Template = routeTemplate,
                    Order = customRouteAttr.Order,
                    Name = customRouteAttr.Name
                }
            });
        }
    }
}

步骤3:注册路由约定到DI容器

在Program.cs里配置控制器服务时,把这个约定添加进去:

var builder = WebApplication.CreateBuilder(args);

// 添加控制器并注册自定义路由约定
builder.Services.AddControllers(options =>
{
    options.Conventions.Add(new CustomRouteConvention(builder.Configuration));
});

var app = builder.Build();

// 其他中间件配置...
app.MapControllers();

app.Run();

这样一来,当你在控制器上标记[CustomRoute]时,路由约定会自动为它生成包含serverKey的路由模板,完美解决了依赖注入的问题。


通用场景的解决方案(非路由Attribute)

如果你的自定义Attribute不是路由相关的(比如授权、验证类的Attribute),可以采用「标记Attribute + DI管理的逻辑服务」的模式:

  1. 定义标记用的Attribute:
public class MyCustomAttribute : Attribute
{
    // 可以存储一些标识参数,供后续逻辑使用
    public string OperationKey { get; set; }
}
  1. 创建处理逻辑的服务:
public interface IMyCustomService
{
    void Execute(MyCustomAttribute attr, object target);
}

public class MyCustomService : IMyCustomService
{
    private readonly IConfiguration _configuration;

    // 这里正常注入依赖
    public MyCustomService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Execute(MyCustomAttribute attr, object target)
    {
        // 在这里使用_configuration和attr的参数处理业务逻辑
        var serverKey = _configuration.GetSection("serverkey").Value;
        // ...你的逻辑代码
    }
}
  1. 在合适的时机触发逻辑:
    比如在ActionFilter中,通过反射获取Attribute,再从DI容器中拿到服务执行逻辑:
using Microsoft.AspNetCore.Mvc.Filters;

public class MyCustomActionFilter : IAsyncActionFilter
{
    private readonly IServiceProvider _serviceProvider;

    public MyCustomActionFilter(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // 从当前Action的元数据中找到MyCustomAttribute
        var attr = context.ActionDescriptor.EndpointMetadata.OfType<MyCustomAttribute>().FirstOrDefault();
        if (attr != null)
        {
            // 创建作用域,获取服务实例
            using var scope = _serviceProvider.CreateScope();
            var service = scope.ServiceProvider.GetRequiredService<IMyCustomService>();
            service.Execute(attr, context.Controller);
        }

        await next();
    }
}

最后注册服务和Filter:

builder.Services.AddScoped<IMyCustomService, MyCustomService>();
builder.Services.AddControllers(options =>
{
    options.Filters.Add<MyCustomActionFilter>();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 18:34:09