在没有 IServiceProvider 的新实例的情况下指定自定义 IModelBinderProvider?
Specify custom IModelBinderProvider without new instance of IServiceProvider?
我的 Startup
class 中有以下代码,它使用 IModelBinderProvider
的自定义实例。大多数输入格式化程序需要一个 ILogger
实例,所以我需要一个 ILoggerFactory
,为此我想使用配置的实例,它以指定的详细程度记录到指定的目的地。我正在从新建的 IServiceProvider
:
中获取 ILoggerFactory
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'.
我看了一下这个问题:。但是,我的代码是 AddMvcCore
的 lambda,它正在配置 options
对象。换句话说,在调用 Configure
时,已经定义了 MVC 选项。
有没有办法在这里做正确的事情,即防止 IServiceProvider
的无关实例?
在配置选项时有几种注入服务的方法。第一种方法是使用 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>
的实现创建单独的 class,但它的可注入依赖项数量有限。第二种方式可以任意注入,适用于大量的配置代码。
您无需构建 ServiceProvider 来解析 ILoggerFactory 即可将其作为参数传递。
在您的 MyCustomBinderProvider 中,您有权解析 ILoggerFactory,我认为您应该有这样的东西
public class MyCustomBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(CustomDto))
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new MyCustomBinder(logger);
}
return null;
}
}
我的 Startup
class 中有以下代码,它使用 IModelBinderProvider
的自定义实例。大多数输入格式化程序需要一个 ILogger
实例,所以我需要一个 ILoggerFactory
,为此我想使用配置的实例,它以指定的详细程度记录到指定的目的地。我正在从新建的 IServiceProvider
:
ILoggerFactory
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'.
我看了一下这个问题:AddMvcCore
的 lambda,它正在配置 options
对象。换句话说,在调用 Configure
时,已经定义了 MVC 选项。
有没有办法在这里做正确的事情,即防止 IServiceProvider
的无关实例?
在配置选项时有几种注入服务的方法。第一种方法是使用 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>
的实现创建单独的 class,但它的可注入依赖项数量有限。第二种方式可以任意注入,适用于大量的配置代码。
您无需构建 ServiceProvider 来解析 ILoggerFactory 即可将其作为参数传递。
在您的 MyCustomBinderProvider 中,您有权解析 ILoggerFactory,我认为您应该有这样的东西
public class MyCustomBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(CustomDto))
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new MyCustomBinder(logger);
}
return null;
}
}