如何在自定义类中使用.Net核心依赖项注入



这是一个新手问题。在ASP.NET Core 3.1 中,我很难从自己的自定义类中访问依赖项注入的服务

我可以从控制器或剃刀页面中访问服务,例如,我可以获得配置和数据上下文信息:

public class DetailModel : PageModel
{
private readonly MyDataContext  _context;
private readonly IConfiguration _config;
public DetailModel(MyDataContext context, IConfiguration config)
{
_context = context;
_config = config;   
}
etc......
}

我现在希望从一个自定义类的构造函数访问这些,该类不是控制器或剃刀页面。例如,我使用的是:

public class ErrorHandling
{
private readonly MyDataContext  _context;
private readonly IConfiguration _config;

public ErrorHandling(MyDataContext context, IConfiguration config)
{
_context = context;
_config = config;   
}
}

问题是,当我实例化我的类时,它坚持要我将服务值传递到构造函数:

var myErrorHandler =  new ErrorHandling(`<wants me to pass context and config values here>`)

这违背了DI的全部观点。我想我错过了一些基本的东西!

我错过了什么?

您也可以在Startup.cs:中将ErrorHandling注册为服务

public void ConfigureServices(IServiceCollection services)
{
// other stuff..
services.AddScoped<ErrorHandling>(); // this should work as long as both 'MyDataContext' and 'IConfiguration' are also registered
}

如果您在页面模型中需要ErrorHandling的实例,您可以在构造函数中指定它,ASP.NET Core将在运行时为您解析它。

这样你就不必new它:

public class DetailModel : PageModel
{
private readonly MyDataContext  _context;
private readonly IConfiguration _config;
private readonly ErrorHandling _errorHandling;
public DetailModel(ErrorHandling errorHandling, MyDataContext context, IConfiguration config)
{
_context = context;
_config = config;   
_errorHandling = errorHandling;
}
}

这篇文章可能很有用:ASP.NET Core 中的依赖项注入

如果您不想注册为服务,可以使用ActivatorUtilities.CreateInstance来解决ErrorHandling。

使用直接和/或从IServiceProvider提供的构造函数参数实例化类型。

例如:

// IServiceProvider serviceProvider = ...;
var errorHandling = ActivatorUtilities.CreateInstance<ErrorHandling>(serviceProvider);

但是您需要小心这个解决方案:

  1. ServiceProvider作用域应等于依赖对象(MyDataContextIConfiguration(。否则,您将得到一个异常,如:

    var errorHandling = ActivatorUtilities.CreateInstance<ErrorHandling>(app.ApplicationServices);
    // An exception of type 'System.InvalidOperationException' occurred 
    // in Microsoft.Extensions.DependencyInjection.dll but was not handled in user cod
    // e: 'Cannot resolve scoped service 'three.MyDataContext' from root provider.'
    

    为此,您可以创建一个范围来解决ErrorHandling:

    using (var scope = app.ApplicationServices.CreateScope())
    {
    var errorHandling = ActivatorUtilities.CreateInstance<ErrorHandling>(scope.ServiceProvider);
    }
    
  2. 依赖项注入服务不会在IDisposable实例上调用Dispose,甚至超出范围。

    为此,您应该自己调用Dispose((:

    using (var scope = app.ApplicationServices.CreateScope())
    {
    using var disposablClass = ActivatorUtilities.CreateInstance<DisposablClass>(scope.ServiceProvider);
    }
    
  3. ActivatorUtilities。即使您使用相同的ServiceProvider:,CreateInstance也会新建一个实例

    using (var scope = app.ApplicationServices.CreateScope())
    {
    var errorHandling1 = ActivatorUtilities.CreateInstance<ErrorHandling>(scope.ServiceProvider);
    Console.WriteLine(errorHandling1.GetHashCode());
    // 11903911
    var errorHandling2 = ActivatorUtilities.CreateInstance<ErrorHandling>(scope.ServiceProvider);
    Console.WriteLine(errorHandling2.GetHashCode());
    // 40026340
    }
    

最新更新