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

如何在配置自定义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容器构建完成后能正确获取所需服务:

  1. 先将MyDisplayMetadataProvider注册到DI容器(匹配Singleton生命周期):
builder.Services.AddSingleton<MyDisplayMetadataProvider>();
  1. 实现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);
    }
}
  1. 注册这个配置类:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:23:21