簡體   English   中英

一個人如何在MVC上下文之外使用依賴項注入?

[英]How does one use dependency injection outside of an MVC context?

核心問題

出於某種原因,我看到的每個用於依賴項注入的示例都與MVC配對,就像在Web項目之外沒有其他東西一樣。 我對此有疑問,因為使用依賴注入的MVC一直存在矛盾,但是它通過依賴關系解析器傳遞這些依賴關系 ,在我看來, 依賴關系解析器只是服務定位器的另一個名稱。

簡單控制台應用程序中的DI

綜上所述,如何在簡單的控制台應用程序中使用DI?

  • 如果沒有方便的Dependency Resolver可供使用。 我如何實際執行DI的注入部分?
  • 我在服務定位器周圍看到了不贊成的聲音,但是您還能做什么?
  • 您不能通過容器,因為這也是一種不好的做法,但是還有什么可以做的呢?

常見的困惑/沮喪

我看到很多程序員犯了這些錯誤,老實說,我不能為此而責怪他們。 MVC之外沒有一個明確的解決方案,它顯然使用了可怕的 Service Locator。

DI引入了自己的問題

我對此不滿意的事情是通過一個對象鏈傳遞一個依賴關系,以在深層嵌套的代碼段中使用它。 這只是感覺不對。

這是我正在努力表達自己關心的事情的典型例子。 我不喜歡通過一個類傳遞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還是控制台應用程序都是實現細節。

在這種情況下,經過簡化的示例並未遵循干凈的設計,因為EntryPointServiceClass緊密耦合,並且還違反了“ 顯式依賴原則”

在此示例中, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM