本文主要是詳解一下在ASP.NET Core中,自帶的IOC容器相關的使用方式和注入類型的生命週期.html
這裏就不詳細的贅述IOC是什麼 以及DI是什麼了.. emm..不懂的能夠自行百度.編程
ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自帶的IOC容器)框架
ASP.NET Core中使用IOC三部曲(二.採用Autofac來替換IOC容器,並實現屬性注入)asp.net
ASP.NET Core中使用IOC三部曲(三.採用替換後的Autofac來實現AOP攔截)ide
上一篇咱們說過ASP.NET Core中自帶的IOC容器是屬於輕量級的,功能並非不少,只是提供了基礎功能而已..模塊化
因此今天咱們主要講講如何採用Autofac來替換IOC容器,並實現屬性注入函數
注意:本文須要讀者理解DI IOC並使用過相關框架.post
首先,咱們須要從nuget引用相關的包.測試
Autofacui
Autofac.Extensions.DependencyInjection(這個包擴展了一些微軟提供服務的類.來方便替換autofac)
而後,咱們修改Startup中的ConfigureServices代碼以下:
public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddDbContext<BloggingContext>(); services.AddDirectoryBrowser(); var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterModule<DefaultModule>(); containerBuilder.Populate(services); var container = containerBuilder.Build(); return new AutofacServiceProvider(container); }
這裏咱們使用了AutoFac的功能之一,模塊化注入.也就是RegisterModule 這裏, DefaultModule是咱們的注入模塊,代碼很簡單,以下:
public class DefaultModule : Module { protected override void Load(ContainerBuilder builder) { //注入測試服務 builder.RegisterType<TestService>().As<ITestService>(); } }
解釋一下,在上面的代碼中,咱們配置IServiceProvider從Autofac容器中解析(設置一個有效的Autofac服務適配器)。
而後在整個框架中使用它來解析控制器的依賴關係,並在HttpContext上公開全部其餘用例的服務定位。
這樣咱們就完成了初步的Autofac容器替換.下面咱們建立控制器來看看效果.代碼以下:
public class AutoDIController : Controller { private readonly ITestService _testService; public AutoDIController(ITestService testService) { _testService = testService; } // GET: AutoDI public ActionResult Index() { ViewBag.date = _testService.GetList("Name"); return View(); } }
當框架(經過一個命名爲DefaultControllerActivator的服務)要建立一個控制器的實例時,它會解析IServiceProvider的全部構造函數依賴項.在上面的代碼中,它會使用Autofac容器來解析產生類。
這樣就能初步的達到咱們替換IOC容器的的效果了..
可是,這個操做過程與asp.net MVC的不一樣之處在於.控制器自己不會從容器中解析出來,因此服務只能從它的構造器參數中解析出來。
因此.這個過程,讓咱們沒法使用Autofac的一些更高級功能.好比屬性注入(關於屬性注入的好壞..屬於仁者見仁智者見智的東西,這裏咱們不討論它是好仍是壞.)
咱們回到Autofac設置代碼,並設置屬性注入以下:
var containerBuilder = new ContainerBuilder(); //模塊化注入 containerBuilder.RegisterModule<DefaultModule>(); //屬性注入控制器 containerBuilder.RegisterType<AutoDIController>().PropertiesAutowired(); containerBuilder.Populate(services);
注入模塊的代碼修改以下:
//屬性注入 builder.RegisterType<TestService>().As<ITestService>().PropertiesAutowired();
而後修改咱們的控制器代碼以下:
public class AutoDIController : BaseController { public ITestService _testService { get; set; } // GET: AutoDI public ActionResult Index() { ViewBag.date = _testService.GetList("Name"); return View(); }
}
這裏咱們剔除了控制器的構造函數.
咱們運行代碼,會發現_testService 爲null,因此根本沒有注入成功.失敗的緣由上面咱們已經解釋過了...可是仍是強調一下吧..
雖然控制器的構造函數依賴性將由MVC從IServiceProvider解決(也就是咱們以前構造函數注入的例子),
可是控制器自己的實例(以及它的處理)倒是由框架建立和擁有的,而不是由容器全部。
那麼咱們該如何改變控制器自己的建立和全部者呢?
咱們會在Microsoft.Extensions.DependencyInjection中找到一個方法.叫作AddControllersAsServices
它的註釋翻譯過來爲:將控制器的寄宿器轉爲註冊的服務(也就是咱們替換的autofac).
可是,注意..這裏雖然是將控制的全部者改爲了autofac,可是咱們仍是不能使用相關的屬性注入方法.
因此,咱們到GITHUB上來看看這個方法源碼以下.(這就是開源的好處...):
public static IMvcBuilder AddControllersAsServices(this IMvcBuilder builder) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } var feature = new ControllerFeature(); builder.PartManager.PopulateFeature(feature); foreach (var controller in feature.Controllers.Select(c => c.AsType())) { builder.Services.TryAddTransient(controller, controller); } builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>()); return builder; }
咱們會發現最後一句..
builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
意思是用ServiceBasedControllerActivator替換DefaultControllerActivator(意味着框架如今會嘗試從IServiceProvider中解析控制器實例)
..這下終於真相大白了..
咱們只須要修改配置服務的代碼以下:
public IServiceProvider ConfigureServices(IServiceCollection services) { //替換控制器全部者 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>()); services.AddMvc(); services.AddDbContext<BloggingContext>(); services.AddDirectoryBrowser(); var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterModule<DefaultModule>(); //採用屬性注入控制器 containerBuilder.RegisterType<AutoDIController>().PropertiesAutowired(); // containerBuilder.RegisterTypes(feature.Controllers.Select(ti => ti.AsType()).ToArray()).PropertiesAutowired(); containerBuilder.Populate(services); var container = containerBuilder.Build(); return new AutofacServiceProvider(container); }
注意,替換的方法必定要在addMVC以前..
而後咱們運行咱們的控制器代碼.效果如圖:
如圖所示,_testService已經被實例化了.說明咱們的屬性注入就成功了~
本篇到此就結束了,下篇咱們講解,如何使用Autofac的高級功能來實現咱們的切面編程(AOP)
喜歡的請點個推薦和關注,~有問題也但願各位批評指正~.