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

DI parameters to class library without controller

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

我可以绕过 Controller 直接注入一个 Class 库吗?​​

举例说明我正在尝试做的事情,假设我有 appSettings.json 和

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

然后是 Class 电子邮件服务库

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)
   {
      ....
   }
}

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

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 class 库中,我希望能够从 BusinessLayer(或任何其他地方)调用 SendErrorEmail。

DoWork.cs

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

但它只是失败并出现空异常。启动中的 DI 没有创建 EmailService 来代替 IEmailService,我猜参数也不在那里。

感谢您提供的任何帮助。

----编辑----

我最终只是改用 AutoFac 进行 DI。它能够完成我正在寻找的东西。接受下面的答案给Phantom尝试协助的分数。

几件事:

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

  • 其次,在服务集合中,您要添加一个 "Scoped" 依赖项(在 ConfigureServices 方法中)。 "scoped" 依赖仅在 (http)Request 上创建,通常是通过调用控制器。从您的代码和解释来看,您似乎想为 IEmailService 接口添加一个 Singleton 对象。因此,除了使用 AddSingleton 添加 Scoped 依赖项 - 正如您所做的那样,您还可以在对 AddSingleton 的调用中创建特定对象 - 这意味着每次请求时都会提供该对象(例如,通过 class 构造函数)。如果您将它用作单例,您还应该确保它是线程安全的。或者,您也可以使用 AddTransient 添加依赖项 - 如果您使用它,每次请求时都会创建一个 new 对象。

更新: 示例代码

修改您的 ConfigureServices 以使 EmailService 成为 Transient(这意味着每次请求此服务时都会有一个新对象):

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

您的 "DoWork" class 应该在构造函数中请求 EMail 服务:

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 class 的对象。为此,一个想法是为 DoWork class 本身创建一个接口,然后也为该接口设置容器。然后,无论您想在何处使用 DoWork 实现,都可以 "request" DoWork 的接口。或者直接使用容器创建实例。