没有控制器的类库的DI参数

时间:2019-01-17 02:58:31

标签: dependency-injection asp.net-core-2.1 class-library

所以我不确定是否只是缺少一些东西,但是基本上我在asp.net内核中看到的每个DI示例都显示了appSettings.json文件中的参数通过控制器中的构造函数的传递,然后传递给任何东西其他。

我可以绕过Controller并直接注入类库吗?

举一个我想做的事的例子,假设我有appSettings.json与

"EmailSettings":{"smtpServer":"mail.example.com", "port":123, "sendErrorsTo":"errors@example.com"}

然后创建一个用于EmailServices的类库

EmailSettings.cs

public class EmailSettings{
   public string smtpServer {get;set;}
   public int port {get;set;}
   public string sendErrorsTo {get;set;}
}

IEmailService.cs

public interface IEmailService
{
   void SendErrorEmail(string method, Exception ex);
}

和EmailService.cs

public class EmailService :IEmailService
{
   private readonly EmailSettings _emailSettings;
   public EmailService(EmailSettings emailSettings)
   {
      _emailSettings = emailSettings;
   }
   public void SendErrorEmail(string method, Exception ex)
   {
      ....
   }
}

主要asp.net核心应用程序中的Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
   services.AddScoped<IEmailService, EmailService>(p => {
      return new EmailService(p.GetService<EmailSettings>());
   });
   ...
}

我不希望通过控制器加载EmailServices或appsetting.json参数,然后再将其加载到BusinessLayer类库中,我希望能够从BusinessLayer(或其他任何地方)调用SendErrorEmail。

DoWork.cs

public MakeItWork()
{
   try
   {...}
   catch (exception ex)
   {
      IEmailService.SendErrorEmail("BAL - MakeItWork",ex)
   }
}

但是它只是失败,并带有null异常。初创公司中的DI不会代替IEmailService创建EmailService,而且我想参数也不在那里。

感谢您提供的任何帮助。

----编辑----

我最终只是切换到使用AutoFac for DI。它能够完成我一直在寻找的东西。接受了以下答案,为Phantom提供了帮助的要点。

1 个答案:

答案 0 :(得分:1)

几件事:

  • 在您的MakeItWork()方法中,您有使用接口名称“调用”方法的代码-甚至不确定该如何编译。您需要使用实现该接口的类的对象在运行时实际进行方法调用。例如,在DoWork类中,可以有一个构造函数,该类请求一个实现IEmailService接口的类的实例,并将其存储以供将来在其他方法中使用。

  • 第二,在Services集合中,您正在添加“作用域”依赖项(在ConfigureServices方法中)。仅在(http)请求上通常通过对控制器的调用来创建“作用域”依赖性。根据您的代码和说明,您似乎想为IEmailService接口添加一个Singleton对象。因此,您不必像之前那样使用AddSingleton添加作用域依赖性,也可以在对AddSingleton的调用中创建特定对象-这意味着每次您请求时都会提供该对象(通过类的构造函数)。如果将其作为单例使用,则还应确保它是线程安全的。另外,您也可以使用AddTransient添加依赖项-如果使用此依赖项,则每次您请求时都会创建一个 new 对象。

更新: 示例代码

修改您的ConfigureServices以将EmailService设置为Transient(这意味着每次请求此服务时都会创建一个新对象):

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
   services.AddTransient<IEmailService, EmailService>();
   ...
}

您的“ DoWork”类应在构造函数中请求电子邮件服务:

public class DoWork()
{

private IEmailService _emailService;

//Dependency should be injected here
public DoWork(IEmailService emailService)
{
    _emailService = emailService;
}


public MakeItWork()
{
   try
   {...}
   catch (exception ex)
   {
      //Use the saved email service object to do your work
      _emailService.SendErrorEmail("BAL - MakeItWork", ex)
   }
}

}

这还没有结束。问题仍然在于如何创建DoWork类的对象。为此,一个想法是为DoWork类本身创建一个接口,然后也为该接口设置容器。然后,无论您想使用DoWork实现如何,都可以“请求” DoWork接口。或直接使用容器创建实例。