在.NET Core控制檯程序中如何使用依賴注入詳解

這篇文章主要給大家介紹了關於在.NET Core控制檯程序中如何使用依賴注入的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑑,下面隨着小編來一起學習學習吧

背景介紹

Dependency Injection:又稱依賴注入,簡稱DI。在以前的開發方式中,層與層之間、類與類之間都是通過new一個對方的實例進行相互調用,這樣在開發過程中有一個好處,可以清晰的知道在使用哪個具體的實現。隨着軟件體積越來越龐大,邏輯越來越複雜,當需要更換實現方式,或者依賴第三方系統的某些接口時,這種相互之間持有具體實現的方式不再合適。爲了應對這種情況,就要採用契約式編程:相互之間依賴於規定好的契約(接口),不依賴於具體的實現。這樣帶來的好處是相互之間的依賴變得非常簡單,又稱鬆耦合。至於契約和具體實現的映射關係,則會通過配置的方式在程序啓動時由運行時確定下來。這就會用到DI。

依賴注入(Dependency Injection), 是面向對象編程中的一種設計原則,可以用來減低代碼之間的耦合度。在.NET Core MVC中

我們可以在Startup.cs文件的ConfigureService方法中使用服務容器IServiceCollection註冊接口及其實現類的映射。

例如,當我們需要訪問Http上下文時,我們需要配置IHttpContextAccessor接口及其實現類HttpContextAccessor

 public void ConfigureServices(IServiceCollection services)
 {
 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
 services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 }

那麼當我們編寫一個.NET Core控制檯程序的時候,我們該如何使用依賴注入呢?

使用內置依賴注入

在.NET Core中,內置依賴注入模塊使用的程序集是Microsoft.Extensions.DependencyInjection

所以如果希望在控制檯程序中使用內置依賴注入,我們首先需要使用NUGET添加對Microsoft.Extensions.DependencyInjection程序集的引用。

PM> Install-Package Microsoft.Extensions.DependencyInjection

這裏爲了說明如何使用.NET Core內置的依賴注入模塊, 我們創建以下2個服務接口。

 public interface IFooService
 {
 void DoThing(int number);
 }

 public interface IBarService
 {
 void DoSomeRealWork();
 }

然後我們針對這2個服務接口,添加2個對應的實現類

 public class BarService : IBarService
 {
 private readonly IFooService _fooService;
 public BarService(IFooService fooService)
 {
  _fooService = fooService;
 }

 public void DoSomeRealWork()
 {
  for (int i = 0; i < 10; i++)
  {
  _fooService.DoThing(i);
  }
 }
 }

 public class FooService : IFooService
 {
 private readonly ILogger<FooService> _logger;
 public FooService(ILoggerFactory loggerFactory)
 {
  _logger = loggerFactory.CreateLogger<FooService>();
 }

 public void DoThing(int number)
 {
  _logger.LogInformation($"Doing the thing {number}");
 }
 }

代碼解釋

  • BarService類構造函數依賴了一個IFooService接口的實現
  • FooService類構造函數依賴一個ILoggerFactory接口的實現
  • FooService中,我們輸出了一個Information級別的日誌

在以上實現類代碼中,我們使用了.NET Core內置的日誌模塊, 所以我們還需要使用NUGET添加對應的程序集Microsoft.Extensions.Logging.Console

PM> Install-Package Microsoft.Extensions.Logging.Console

最後我們來修改Program.cs, 代碼如下

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

 public class Program
 {
 public static void Main(string[] args)
 {
  //setup our DI
  var serviceProvider = new ServiceCollection()
  .AddLogging()
  .AddSingleton<IFooService, FooService>()
  .AddSingleton<IBarService, BarService>()
  .BuildServiceProvider();

  //configure console logging
  serviceProvider
  .GetService<ILoggerFactory>()
  .AddConsole(LogLevel.Debug);

  var logger = serviceProvider.GetService<ILoggerFactory>()
  .CreateLogger<Program>();
  logger.LogInformation("Starting application");

  //do the actual work here
  var bar = serviceProvider.GetService<IBarService>();
  bar.DoSomeRealWork();

  logger.LogInformation("All done!");

 }
 }

代碼解釋

  • 這裏我們手動實例化了一個ServiceCollection類, 這個類是IServiceCollection>接口的一個實現類,它就是一個.NET Core內置服務容器。
  • 然後我們在服務容器中註冊了IFooService接口的實現類FooService以及IBarService接口的實現類BarService。
  • 當時需要從服務容器中獲取接口類的對應實現類時,我們只需要調用服務容器類的GetSerivce方法。

最終效果

運行程序,我們期望的日誌,正確的輸出了

info: DIInConsoleApp.Program[0]
      Start application.
info: DIInConsoleApp.FooService[0]
      Doing the thing 0
info: DIInConsoleApp.FooService[0]
      Doing the thing 1
info: DIInConsoleApp.FooService[0]
      Doing the thing 2
info: DIInConsoleApp.FooService[0]
      Doing the thing 3
info: DIInConsoleApp.FooService[0]
      Doing the thing 4
info: DIInConsoleApp.FooService[0]
      Doing the thing 5
info: DIInConsoleApp.FooService[0]
      Doing the thing 6
info: DIInConsoleApp.FooService[0]
      Doing the thing 7
info: DIInConsoleApp.FooService[0]
      Doing the thing 8
info: DIInConsoleApp.FooService[0]
      Doing the thing 9
info: DIInConsoleApp.Program[0]
      All done!

使用第三方依賴注入

除了使用內置的依賴注入模塊,我們還可以直接使用一些第三方的依賴注入框架,例如Autofac, StructureMap。

這裏我們來使用StructureMap來替換當前的內置的依賴注入框架。

首先我們需要先添加程序集引用。

PM> Install-Package StructureMap.Microsoft.DependencyInjection

然後我們來修改Program.cs文件,代碼如下

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StructureMap;
using System;

namespace DIInConsoleApp
{
 class Program
 {
 static void Main(string[] args)
 {
  var services = new ServiceCollection().AddLogging();

  var container = new Container();
  container.Configure(config =>
  {
  config.Scan(_ =>
  {
   _.AssemblyContainingType(typeof(Program));
   _.WithDefaultConventions();
  });

  config.Populate(services);
  });

  var serviceProvider = container.GetInstance<IServiceProvider>();

  serviceProvider.GetService<ILoggerFactory>().AddConsole(LogLevel.Debug);

  var logger = serviceProvider.GetService<ILoggerFactory>().CreateLogger<Program>();
  logger.LogInformation("Start application.");

  var bar = serviceProvider.GetService<IBarService>();
  bar.DoSomeRealWork();

  logger.LogInformation("All done!");
  Console.Read();
 }
 }
}

代碼解釋

  • 這裏我們實例化了一個StructureMap的服務容器Container, 並在其Configure方法中配置了接口類及其實現類的自動搜索。這裏使用的是一種約定,接口類必須以字母“I”開頭, 實現類的名字和接口類只相差一個字母“I”, 例IFooService, FooService, IBarService, BarService
  • 後續代碼和前一個例子基本一樣。雖然看起來代碼多了很多,但是實際上這種使用約定的注入方式非常強力,可以省去很多手動配置的代碼。

最終效果

運行程序,代碼和之前的效果一樣

info: DIInConsoleApp.Program[0]
      Start application.
info: DIInConsoleApp.FooService[0]
      Doing the thing 0
info: DIInConsoleApp.FooService[0]
      Doing the thing 1
info: DIInConsoleApp.FooService[0]
      Doing the thing 2
info: DIInConsoleApp.FooService[0]
      Doing the thing 3
info: DIInConsoleApp.FooService[0]
      Doing the thing 4
info: DIInConsoleApp.FooService[0]
      Doing the thing 5
info: DIInConsoleApp.FooService[0]
      Doing the thing 6
info: DIInConsoleApp.FooService[0]
      Doing the thing 7
info: DIInConsoleApp.FooService[0]
      Doing the thing 8
info: DIInConsoleApp.FooService[0]
      Doing the thing 9
info: DIInConsoleApp.Program[0]
      All done!

本篇源代碼 (本地下載

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對神馬文庫的支持。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章