asp.net-mvc - 在没有新的 IServiceProvider 实例的情况下指定自定义 IModelBinderProvider?

标签 asp.net-mvc asp.net-core dependency-injection asp.net-core-mvc 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)
                );
                
                ...
            }
        );
        
        ...
    }
问题是我收到以下警告:
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'.
我看了一下这个问题:Resolving instances with ASP.NET Core DI from within ConfigureServices .但是,我的代码是 AddMvcCore 的 lambda ,这是配置 options目的。换句话说,到时候Configure被调用,MVC 选项已经定义。
有没有办法在这里做正确的事情,即防止 IServiceProvider 的无关实例?

最佳答案

在配置选项时有几种方法可以注入(inject)服务。第一种方法是使用 OptionsBuilder<TOptions>可以通过使用扩展方法获得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)
                       );
                   });
第二种方法是通过实现 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>();
第一种方法很方便,因为您不必为 IConfigureOptions<Options> 的实现创建单独的类。但它的可注入(inject)依赖项数量有限。第二种方式可以让你注入(inject)任意多,适合大量配置代码。

关于asp.net-mvc - 在没有新的 IServiceProvider 实例的情况下指定自定义 IModelBinderProvider?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66539910/

相关文章:

entity-framework - 使用 Entity Framework 、依赖注入(inject)、工作单元和存储库模式在运行时注入(inject)/管理更改连接字符串

c# - 无法在 asp.net vnext 类库中使用必需的属性

c# - 在 Entity Framework 中调用 AsNoTracking 的位置是否重要

c# - 无法加载文件或程序集 'Microsoft.Azure.Documents.Client - Azure-Table-Api

asp.net-core - .NET Core 中的 wwwroot/dist 与 ClientApp/dist 文件夹

java - 有没有办法在所有 spring 上下文初始化后调用 bean 中的方法

c# - TDD 模拟篮子里的所有鸡蛋?

asp.net-mvc - 查找 System.Web.Mvc

asp.net-mvc - 在 ASP.NET MVC 中编写表单的最佳方法是什么?

c# - 如何连续监听 ASP.NET Core 应用程序中的 Pub/Sub 消息?