在ConfigureServices中使用DI?

Rob*_*III 2 c# dependency-injection .net-core asp.net-core-webapi

我已经实现了一个自定义的InputFormatter(MyInputFormatter):

public class MyInputFormatter : SystemTextJsonInputFormatter
{
    private readonly IMyDepenency _mydependency;

    public CustomInputFormatter(
        JsonOptions options, 
        ILogger<SystemTextJsonInputFormatter> logger, 
        IMyDependency myDependency
     ) : base(options, logger)
    {
        _mydependency = myDependency ?? throw new ArgumentNullException(nameof(myDependency));
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        //...
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,根据文档我需要按如下方式使用它:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.InputFormatters.Insert(0, new MyInputFormatter(...));
    });
}
Run Code Online (Sandbox Code Playgroud)

但是,正如您所看到的,我CustomInputFormatter需要一些构造函数参数并且需要一些服务,但我不清楚如何使用 DI 来解析这些服务。我已经阅读了很多像这样的答案/博客/页面,但是输入格式化程序没有任何构造函数参数(因此不需要 DI,只需内联新建一个新实例)或者建议以下内容:

public void ConfigureServices(IServiceCollection services)
{
    var sp = services.BuildServiceProvider();
    services.AddControllers(options =>
    {
        options.InputFormatters.Insert(0, new MyInputFormatter(
            sp.GetService<...>(),
            sp.GetService<...>(),
            sp.GetService<IMyDependency>(),
        ));
    });
}
Run Code Online (Sandbox Code Playgroud)

但我们不应该BuildServiceProvider从打电话ConfigureServices

我该怎么办呢?

pin*_*x33 5

您可以利用选项基础结构并创建一个IConfigureOptions<MvcOptions> . 这项新服务可以承受必要的依赖。它将在第一次(MVC 基础设施)请求时被实例化并“执行”IOptions<MvcOptions>

public class ConfigureMvcOptionsFormatters : IConfigureOptions<MvcOptions> 
{ 
   private readonly ILoggerFactory _factory;
   private readonly JsonOptions _jsonOpts;
   private readonly IMyDependency _depend;
   public ConfigureMvcOptionsFormatters(IOptions<JsonOptions> options, ILoggerFactory loggerFactory, IMyDependency myDependency)
   {
      _factory = loggerFactory;
      _jsonOpts = options.Value;
      _depend = myDependency;
   } 

   public void Configure(MvcOptions options)
   { 
      var logger = _factory.CreateLogger<SystemTextJsonInputFormatter>();
      var formatter =  new MyInputFormatter(_jsonOpts, logger, _depend);
      options.InputFormatters.Insert(0, formatter);
   }
} 
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过调用以下扩展方法来注册您的类以运行其IConfigureOptions实现:ConfigureOptions<T>()IServiceCollection

public void ConfigureServices(IServiceCollection services)
{
  services.AddControllers();
  services.ConfigureOptions<ConfigureMvcOptionsFormatters>();
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用选项构建器及其Configure回调,将您的依赖项指定为通用参数。

public void ConfigureServices(IServiceCollection services)
{
  services.AddControllers();
  services.AddOptions<MvcOptions>()
          .Configure<IOptions<JsonOptions>, ILoggerFactory, IMyDependency>(
              (o, j, l, d) => o.InputFormatters.Insert(0, new MyInputFormatter(j.Value, l.CreateLogger<SystemTextJsonInputFormatter>(), d)
          );
}
Run Code Online (Sandbox Code Playgroud)

注意:我一直在使用,ILoggerFactory因为我不相信基础设施会将其注入ILogger<ClassA>ClassB. 不过,我承认我从未尝试过,也没有靠近计算机进行验证。如果确实允许,您可以直接指定您需要的类型。