vs新建的.net core項目內置了依賴注入功能,本文簡單地展示如何使用core的依賴注入,以及使用IOC容器(unity)來替換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中原有的依賴注入。