所以我不确定是否只是缺少一些东西,但是基本上我在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提供了帮助的要点。
答案 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接口。或直接使用容器创建实例。