在没有新的 IServiceProvider 实例的情况下指定自定义 IModelBinderProvider?

fer*_*olo 4 asp.net-mvc dependency-injection asp.net-core-mvc asp.net-core asp.net-core-3.1

我的类中有以下代码Startup,它使用IModelBinderProvider. 大多数输入格式化程序需要一个ILogger实例,所以我需要有一个ILoggerFactory,为此我想使用配置的一个,它以指定的详细程度记录到指定的目的地。我正在ILoggerFactory从一个新建的IServiceProvider

    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        services.AddMvcCore(
            options =>
            {
                ...
            
                var serviceProvider = services.BuildServiceProvider();
                var loggerFactory = serviceProvider.GetService<ILoggerFactory>();

                options.ModelBinderProviders.Clear();
                options.ModelBinderProviders.Add(
                    new MyCustomBinderProvider(options.InputFormatters, loggerFactory)
                );
                
                ...
            }
        );
        
        ...
    }
Run Code Online (Sandbox Code Playgroud)

问题是我收到以下警告:

Startup.cs(62, 43): [ASP0000] Calling 'BuildServiceProvider' from application code results in an
                    additional copy of singleton services being created. Consider alternatives such
                    as dependency injecting services as parameters to 'Configure'.
Run Code Online (Sandbox Code Playgroud)

我看了一下这个问题:Resolving instances with ASP.NET Core DI from inside ConfigureServices。但是,我的代码是 的 lambda AddMvcCore,它正在配置options对象。换句话说,在Configure调用 时,MVC 选项已经定义。

有没有办法在这里做正确的事情,即防止无关的实例IServiceProvider

Kin*_*ing 5

在配置选项时有几种方法可以注入服务。第一种方法是使用OptionsBuilder<TOptions>可以通过使用扩展方法获得的an IServiceCollection.AddOptions,如下所示:

services.AddOptions<MvcOptions>()
         //first arg is always of TOptions, 
         //injectable dependencies start from the second arg
        .Configure((MvcOptions o, ILoggerFactory loggerFactory) => {
                       o.ModelBinderProviders.Insert(0,
                          new MyCustomBinderProvider(o.InputFormatters, loggerFactory)
                       );
                   });
Run Code Online (Sandbox Code Playgroud)

第二种方法是实现一个IConfigureOptions<TOptions>(或IPostConfigureOptions<TOptions>),如下所示:

public class ConfigureMvcOptions : IConfigureOptions<MvcOptions>
{
    readonly ILoggerFactory _loggerFactory;
    public ConfigureMvcOptions(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory;
    }
    public void Configure(MvcOptions options)
    {
        options.ModelBinderProviders.Insert(0,
                  new MyCustomBinderProvider(options.InputFormatters, _loggerFactory)
               );
    }
}

//then configure it like this:
services.ConfigureOptions<ConfigureMvcOptions>();
Run Code Online (Sandbox Code Playgroud)

第一种方法很方便,因为您不必为实现而创建单独的类,IConfigureOptions<Options>但它具有有限数量的可注入依赖项。第二种方式可以让你注入任意多,适合大量配置代码。