ASP.NET Core中使用IOC三部曲(二.采用Autofac來替換IOC容器,並實現屬性注入)


前言

本文主要是詳解一下在ASP.NET Core中,自帶的IOC容器相關的使用方式和注入類型的生命周期.

這里就不詳細的贅述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度.

目錄

ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自帶的IOC容器)

ASP.NET Core中使用IOC三部曲(二.采用Autofac來替換IOC容器,並實現屬性注入)

ASP.NET Core中使用IOC三部曲(三.采用替換后的Autofac來實現AOP攔截)

 

正文

上一篇我們說過ASP.NET Core中自帶的IOC容器是屬於輕量級的,功能並不是很多,只是提供了基礎功能而已..

所以今天我們主要講講如何采用Autofac來替換IOC容器,並實現屬性注入

注意:本文需要讀者理解DI IOC並使用過相關框架.

1.將默認的IOC容器替換為Autofac

 首先,我們需要從nuget引用相關的包.

Autofac

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的一些更高級功能.比如屬性注入(關於屬性注入的好壞..屬於仁者見仁智者見智的東西,這里我們不討論它是好還是壞.)

 

2.如何使用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)

喜歡的請點個推薦和關注,~有問題也希望各位批評指正~.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM