1. 程式人生 > 實用技巧 >.net core的依賴注入

.net core的依賴注入

【摘要】

  vs新建的.net core專案內建了依賴注入功能,本文簡單地展示如何使用core的依賴注入,以及使用IOC容器來替換core自帶的依賴注入容器。

【正文】

1.使用core專案的依賴注入

  新建.net core5 webapi專案,建立MathBook.cs、EnglishBook.cs、Ibook.cs檔案

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace app
{
    public class MathBook: Ibook
    {
        
public string read() { return "看數學書"; } } }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace app
{
    public class EnglishBook: Ibook
    {
        public string read()
        {
            return "看英語書";
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace app
{
    public interface Ibook
    {
        string read();
    }
}

  在Startup.cs中嘗試註冊例項和呼叫例項。

namespace app
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
       //IserviceCollection提供註冊 services.AddSingleton
<Ibook, MathBook>(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
       //IServiceProvider提供例項
app.ApplicationServices獲取
       var provider = app.ApplicationServices;

            //// 輸出
            var result = provider.GetService<Ibook>();
            Console.WriteLine(result.read());
        }
    }
}

執行程式,獲得結果。

  ServiceCollection註冊例項有三個方法,AddTransient、AddSingleton、AddScoped。對應提供的例項會有不同生命週期。

  Transient,每次呼叫GetServie方法都會建立一個新的例項。

  Singleton,整個程式執行期間只建立一個例項。

  Scoped,在同一個scope中,只建立一個例項。在一次http請求的整個過程中,預設共用一個scope。

  .net core專案已經作了依賴注入的實現,直接使用便可。

public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<Ibook, MathBook>();//註冊例項

            services.AddControllers();//使用api
        }
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace app.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BookController : ControllerBase
    {
        private Ibook _book;
        public BookController(Ibook book)
        {
            this._book = book;
        }

        [Route("toRead")]
        [HttpGet]
        public string toRead()
        {
            return _book.read();
        }
    }
}

  呼叫介面,可以獲得結果。

2.替換成其它ioc容器

  原有的依賴注入容器在面對大型專案會有些麻煩,原因是隻能一個個進行註冊例項,有可能光是引用名稱空間就佔了幾百行。

  這裡使用unity進行替換。

  安裝unity相關包

  在Program.cs中新增UseUnityServiceProvider()。

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Unity;
using Unity.Microsoft.DependencyInjection;

namespace app
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseUnityServiceProvider()
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

  在Startup.cs中新增ConfigureContainer方法,用來處理untiy容器,往容器中註冊例項。

public void ConfigureContainer(IUnityContainer container)
        {
            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
            fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "unity.config");
            Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
            UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);

            section.Configure(container, "gContainer");//寫法一:給容器載入在配置檔案中name為“gContainer”的<container>
        }

  上面是unity通過讀取配置檔案去註冊,unity.config屬性需要設定為始終複製。

<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
  </configSections>
  <unity>
    <assembly name="app"/>
    <containers>
      <container name="gContainer">
        <register type="app.Ibook" mapTo="app.MathBook" />
      </container>
    </containers>
  </unity>
</configuration>

  Unity.Microsoft.DependencyInjection這個包的作用就是將unity的註冊例項行為轉化到.net core依賴容器,生成例項的生命週期是由.net core內建的容器進行管理。閱讀該包原始碼可以瞭解。

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;

namespace Unity.Microsoft.DependencyInjection
{
    public static class HostingExtension
    {
        private static ServiceProviderFactory _factory;


        public static IHostBuilder UseUnityServiceProvider(this IHostBuilder hostBuilder, IUnityContainer container = null)
        {
            _factory = new ServiceProviderFactory(container);

            return hostBuilder.UseServiceProviderFactory<IUnityContainer>(_factory)
                              .ConfigureServices((context, services) =>
                              {
                                  services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IUnityContainer>>(_factory));
                                  services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(_factory));
                              });
        }

        public static IWebHostBuilder UseUnityServiceProvider(this IWebHostBuilder hostBuilder, IUnityContainer container = null)
        {
            _factory = new ServiceProviderFactory(container);

#if NETCOREAPP1_1
            return hostBuilder.ConfigureServices((services) =>
            {
                services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IUnityContainer>>(_factory));
                services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(_factory));
            });
#else
            return hostBuilder.ConfigureServices((context, services) =>
            {
                services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IUnityContainer>>(_factory));
                services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(_factory));
            });
#endif
        }
    }
}

  大致就是,使用了UseUnityServiceProvider的拓展方法後,unity的註冊例項,除了在unity自己的容器操作,同時還會對.net core的serviceCollection容器進行操作。

  執行程式,呼叫api/Book/toRead介面,成功得到結果。

  至此,成功使用unity去替換實現.net core中原有的依賴注入。