[英]How does one use dependency injection outside of an MVC context?
出於某種原因,我看到的每個用於依賴項注入的示例都與MVC配對,就像在Web項目之外沒有其他東西一樣。 我對此有疑問,因為使用依賴注入的MVC一直存在矛盾,但是它通過依賴關系解析器傳遞這些依賴關系 ,在我看來, 依賴關系解析器只是服務定位器的另一個名稱。
綜上所述,如何在簡單的控制台應用程序中使用DI?
我看到很多程序員犯了這些錯誤,老實說,我不能為此而責怪他們。 MVC之外沒有一個明確的解決方案,它顯然使用了可怕的 Service Locator。
我對此不滿意的事情是通過一個對象鏈傳遞一個依賴關系,以在深層嵌套的代碼段中使用它。 這只是感覺不對。
這是我正在努力表達自己關心的事情的典型例子。 我不喜歡通過一個類傳遞SMTP客戶端依賴項,而只是將其提供給另一個類。 您可能會被迫說“將SmtpClient注入ServiceClass,然后注入EntryPoint”。 在我的示例中,我無法注入ServiceClass,因為它實際上來自於Factory模式。
public static void Main(string[] args)
{
var smtpClient = _container.GetDependency<ISmtpClient>();
//When I do this manually I feel like it defeats the purpose of DI
var ep = new EntryPoint(smtpClient);
ep.RunAProcess();
}
public class EntryPoint
{
private readonly ISmtpClient _smtpClient;
public EntryPoint(ISmtpClient smtpClient)
{
//EntryPoint doesn't use this dependency
_smtpClient = smtpClient;
}
public void RunAProcess()
{
/* More code here */
//ServiceClass actually comes from a Factory, but I didn't
//want to make this example too long
var svc = new ServiceClass(_smtpClient);
svc.Send();
}
}
public class ServiceClass
{
private readonly ISmtpClient _smtpClient;
public ServiceClass(ISmtpClient smtpClient)
{
//ServiceClass uses this dependency
_smtpClient = smtpClient;
}
public void Send()
{
using (var mail = CreateMailMessage(message))
{
_smtpClient.Send(mail);
}
}
}
這是與查詢有關的最接近的SO問題: MVC項目外部的DbContext依賴注入
在MVC之外,您可以使用HostBuilder
參見https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-2.2
總體思路是,它的工作方式與網絡版本非常相似(並且將支持控制台,Windows服務和linux守護程序等)
public static async Task Main(string[] args)
{
var host = new HostBuilder() .
.ConfigureServices(ConfigureServices)
.UseConsoleLifetime()
.Build();
await host.RunAsync();
}
private static void ConfigureServices(HostBuilderContext context, IServiceCollection services)
{
services
.AddTransient<IThing, Thingy>()
.AddTransient<Stuff>()
.AddHostedService<MyService>();
}
您的托管服務就像您的主要入口點一樣,從那里開始會注入東西。
internal class MyService : IHostedService
{
public MyService(Stuff stuff) // injected stuff
{
}
public Task StartAsync(CancellationToken cancellationToken)
{
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
這更多是對設計原理的誤解。
我對通過一系列對象傳遞依賴項以在深層嵌套的代碼中使用依賴項感到不滿意。 這只是感覺不對。
您問題的核心是了解如何應用干凈的設計,以實現松散的耦合和高內聚力。 無論是Asp.Net MVC還是控制台應用程序都是實現細節。
在這種情況下,經過簡化的示例並未遵循干凈的設計,因為EntryPoint
與ServiceClass
緊密耦合,並且還違反了“ 顯式依賴原則” 。
在此示例中, EntryPoint
不是關於其依賴關系的真實EntryPoint
。 如果它不直接使用ISmtpClient
,則不應明確地依賴它來傳遞它。
如果ServiceClass
來自工廠,則應將工廠應用於組合根,然后顯式注入EntryPoint
查看以下重構,以了解我指的是什么
public static void Main(string[] args) {
//ISmtpClient should be injected into ServiceClass
//when resolved by the container or factoty
IService service = _container.GetDependency<IService>();
var ep = new EntryPoint(service);
ep.RunAProcess();
}
public class EntryPoint {
private readonly IService service;
public EntryPoint(IService service) {
this.service = service;
}
public void RunAProcess() {
/* More code here */
service.Send(message);
}
}
public class ServiceClass : IService {
private readonly ISmtpClient _smtpClient;
public ServiceClass(ISmtpClient smtpClient) {
//ServiceClass uses this dependency
_smtpClient = smtpClient;
}
public void Send(Message message) {
using (var mail = CreateMailMessage(message)) {
_smtpClient.Send(mail);
}
}
}
因此,即使您在組合根目錄應用純依賴項注入 ,也只會將實際依賴項注入到目標依賴項中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.