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 的接口。或者直接使用容器创建实例。
所以我不确定我是否只是遗漏了一些东西,但基本上我在 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 的接口。或者直接使用容器创建实例。