【问题标题】:Use DI in ConfigureServices?在 ConfigureServices 中使用 DI?
【发布时间】:2020-07-08 11:18:00
【问题描述】:

我已经实现了一个自定义 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)
    {
        //...
    }
}

现在,根据the documentation我需要使用如下:

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

但是,您可以看到我的CustomInputFormatter 需要一些构造函数参数并且需要一些服务,我不清楚如何使用 DI 来解决这些服务。我已经阅读了很多答案/博客/页面,例如this one,但是 inputformatter 没有任何构造函数参数(因此不需要 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>(),
        ));
    });
}

但我们不应该从ConfigureServices 调用BuildServiceProvider

我该怎么做?

【问题讨论】:

  • 这能回答你的问题吗? Resolving instances with ASP.NET Core DI
  • Ian Kemp 在您的链接中的回答怎么样?这是完全相同的问题(唯一的区别是他使用的是ModelValidatorProviders.Add而不是InputFormatters.Insert

标签: c# .net-core dependency-injection asp.net-core-webapi


【解决方案1】:

您可以使用Options infrastructure 并创建一个IConfigureOptions&lt;MvcOptions&gt; 。这项新服务可以采取必要的依赖关系。它会在某些东西(MVC 基础架构)第一次请求IOptions&lt;MvcOptions&gt;时被实例化并“执行”

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

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

然后,您可以通过调用 ConfigureOptions&lt;T&gt;() extension method on the IServiceCollection 来注册您的类以运行其 IConfigureOptions 实现:

public void ConfigureServices(IServiceCollection services)
{
  services.AddControllers();
  services.ConfigureOptions<ConfigureMvcOptionsFormatters>();
}

或者,您可以将选项构建器与Configure 一起使用,它是回调,将您的依赖项指定为通用参数。

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

注意:我一直在使用ILoggerFactory,因为我不相信基础架构会将ILogger&lt;ClassA&gt; 注入ClassB。但是,我承认我从未尝试过,而且我也没有靠近计算机进行验证。如果实际上允许,您可以直接指定您需要的类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 2013-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多