如何在配置自定义ModelMetadataDetailsProvider时使用依赖注入
解决自定义IDisplayMetadataProvider的依赖注入问题
核心问题分析
你的问题集中在三个关键点:
- 手动实例化
MyDisplayMetadataProvider时无法自动注入依赖; - 误调用了Configuration的
Add方法而非DI容器的服务注册方法; - 忽略了生命周期不匹配:
IDisplayMetadataProvider属于Singleton生命周期(被添加到Options中),但MyDBContext是Scoped服务,直接注入会导致生命周期泄漏。
正确实现方案
步骤1:调整MyDisplayMetadataProvider的构造函数
由于Singleton服务不能直接依赖Scoped的MyDBContext,需要通过IServiceScopeFactory动态创建作用域获取实例,避免生命周期冲突:
public class MyDisplayMetadataProvider : IDisplayMetadataProvider { private readonly IServiceScopeFactory _scopeFactory; private readonly IMemoryCache _memoryCache; // 注入IServiceScopeFactory和IMemoryCache public MyDisplayMetadataProvider(IServiceScopeFactory scopeFactory, IMemoryCache memoryCache) { _scopeFactory = scopeFactory; _memoryCache = memoryCache; } public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { // 使用时创建作用域获取MyDBContext using var scope = _scopeFactory.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<MyDBContext>(); // 后续逻辑:从数据库获取数据 + 缓存处理 // ... } }
步骤2:注册服务并配置Options
通过IConfigureOptions实现延迟配置,确保DI容器构建完成后能正确获取所需服务:
- 先将
MyDisplayMetadataProvider注册到DI容器(匹配Singleton生命周期):
builder.Services.AddSingleton<MyDisplayMetadataProvider>();
- 实现
IConfigureOptions<MvcOptions>来添加提供器:
public class ConfigureMvcOptionsWithDisplayProvider : IConfigureOptions<MvcOptions> { private readonly MyDisplayMetadataProvider _displayProvider; public ConfigureMvcOptionsWithDisplayProvider(MyDisplayMetadataProvider displayProvider) { _displayProvider = displayProvider; } public void Configure(MvcOptions options) { options.ModelMetadataDetailsProviders.Add(_displayProvider); } }
- 注册这个配置类:
builder.Services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureMvcOptionsWithDisplayProvider>();
简化写法(可选)
如果不想单独编写IConfigureOptions实现类,可直接用AddOptions的委托方式:
builder.Services.AddSingleton<MyDisplayMetadataProvider>(); builder.Services.AddOptions<MvcOptions>() .Configure<MyDisplayMetadataProvider>((options, provider) => { options.ModelMetadataDetailsProviders.Add(provider); });
基础服务注册确认
确保MyDBContext和IMemoryCache已正确注册:
// 注册数据库上下文 builder.Services.AddDbContext<MyDBContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // IMemoryCache默认已在ASP.NET Core Web项目中注册,无需额外添加
为什么之前的尝试失败?
- 错误调用
Add<MyDisplayMetadataProvider>():你误使用了IConfigurationBuilder的Add方法(用于添加配置源),而非IServiceCollection的服务注册方法(如AddSingleton<MyDisplayMetadataProvider>()); - 提前调用
builder.Build():一旦构建WebApplication实例,服务集合会被锁定,无法再修改; - 生命周期冲突:直接将Scoped的
MyDBContext注入Singleton提供器,会导致DbContext被长期持有,引发数据一致性问题和资源泄漏。
内容的提问来源于stack exchange,提问作者Philip Stratford
相关产品推荐
相关产品推荐

