NET Core3.1 用 Autofac 實現IOC容器


一、IOC容器

IOC(Inversion of Control,控制反轉),他不是一種技術,只是一種思想,一個重要的面向對象編程的法則,它能指導我們如何設計出松耦合,更優良的程序。

DI(依賴注入)。IOC的一個重點是在系統運行中,動態的向某個對象提供它所需要的其他對象。這一點是通過DI(Dependency Injection,依賴注入)來實現的。

使用依賴注入,有以下優點:

  • 傳統的代碼,每個對象負責管理與自己需要依賴的對象,導致如果需要切換依賴對象的實現類時,需要修改多處地方。同時,過度耦合也使得對象難以進行單元測試。
  • 依賴注入把對象的創造交給外部去管理,很好的解決了代碼緊耦合(tight couple)的問題,是一種讓代碼實現松耦合(loose couple)的機制。
  • 松耦合讓代碼更具靈活性,能更好地應對需求變動,以及方便單元測試。

二、使用——Autofac

1、引入nuget包

在Nuget中引入兩個:Autofac.Extras.DynamicProxy(Autofac的動態代理,它依賴Autofac,所以可以不用單獨引入Autofac)、Autofac.Extensions.DependencyInjection(Autofac的擴展)

 

 

2、在Startup類下面創建 ConfigureContainer 方法

Core 3.0以上版本寫法請注意和2.2是不一樣的,完整代碼如下

        public void ConfigureContainer(ContainerBuilder builder)
        {
            var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
            //注冊要通過反射創建的組件
            //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();

            #region 帶有接口層的服務注入

       //項目引用接口, 服務層和倉儲層的bin文件直接使用,實現解耦 var servicesDllFile = Path.Combine(basePath, "Blog.Core.Services.dll"); var repositoryDllFile = Path.Combine(basePath, "Blog.Core.Repository.dll"); if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile))) { throw new Exception("Repository.dll和service.dll 丟失,因為項目解耦了,所以需要先F6編譯,再F5運行,請檢查 bin 文件夾,並拷貝。"); } // AOP 開關,如果想要打開指定的功能,只需要在 appsettigns.json 對應對應 true 就行。 var cacheType = new List<Type>();// 獲取 Service.dll 程序集服務,並注冊 var assemblysServices = Assembly.LoadFrom(servicesDllFile); builder.RegisterAssemblyTypes(assemblysServices) .AsImplementedInterfaces() .InstancePerDependency() .EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy; .InterceptedBy(cacheType.ToArray());//允許將攔截器服務的列表分配給注冊。 // 獲取 Repository.dll 程序集服務,並注冊 var assemblysRepository = Assembly.LoadFrom(repositoryDllFile); builder.RegisterAssemblyTypes(assemblysRepository) .AsImplementedInterfaces() .InstancePerDependency(); #endregion #region 沒有接口層的服務層注入 //因為沒有接口層,所以不能實現解耦,只能用 Load 方法。 //注意如果使用沒有接口的服務,並想對其使用 AOP 攔截,就必須設置為虛方法 //var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services"); //builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces); #endregion #region 沒有接口的單獨類 class 注入 //只能注入該類中的虛方法 builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love))) .EnableClassInterceptors() .InterceptedBy(cacheType.ToArray()); #endregion }
沒有接口的單獨類 class 注入,只能注入該類中的虛方法
    /// <summary>
    /// 這是愛
    /// </summary>
    public class Love
    {
     //虛方法
public virtual string SayLoveU() { return "I ♥ U"; } }

3、在program類下面build

 
        
public static IHostBuilder CreateHostBuilder(string[] args) =>
   Host.CreateDefaultBuilder(args)
     .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS
     .ConfigureWebHostDefaults(webBuilder =>
     {
         webBuilder
           .UseStartup<Startup>()
           .UseUrls("http://localhost:8081")
           .ConfigureLogging((hostingContext, builder) =>
           {
               builder.ClearProviders();
               builder.SetMinimumLevel(LogLevel.Trace);
               builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
               builder.AddConsole();
               builder.AddDebug();
           });
     });
 
        

4、構造函數方式來注入

依賴注入有三種方式(構造方法注入、setter方法注入和接口方式注入),我們平時基本都是使用其中的構造函數方式實現注入,
        
     //接口
     readonly IAdvertisementServices _advertisementServices; /// <summary> /// 構造函數 /// </summary> /// <param name="advertisementServices"></param> public BlogController(IAdvertisementServices advertisementServices) { _advertisementServices = advertisementServices; }     [HttpGet("{id}", Name = "Get")] public async Task<List<Advertisement>> Get(int id) { //IAdvertisementServices advertisementServices = new AdvertisementServices(); //不依賴注入是需要引用兩個命名空間IServices層和Services層        //使用 return await _advertisementServices.Query(d => d.Id == id); }
 
        

5、程序集注入 —— 實現層級引用的解耦

這是一個學習的思路,大家要多想想,可能會感覺無聊或者沒用,但是對理解項目啟動和加載,還是很有必要的。

1、項目最終只依賴抽象

最終的效果是這樣的:工程只依賴抽象,把兩個實現層刪掉,引用這兩個接口層。

 

 

 

2、配置倉儲和服務層的程序集輸出

將 Blog.Repository 層和 Service 層項目生成地址改成相對路徑,這樣大家就不用手動拷貝這兩個 dll 了,F6編譯的時候就直接生成到了 api 層 bin 下了:


“..\Blog.Core\bin\Debug\”

 

 

 好了,項目啟動就可以運行了


常見錯誤:

經常會遇到一個錯誤:None of the constructors found with ........,

查看你的service服務,是不是用了其他的倉儲repository,但是又缺少了構造函數。

 參考自:https://www.cnblogs.com/laozhang-is-phi/p/9541414.html
如果寫的不明白可以看看大神原文,我是在跟着大神學習的,下節學習AOP切面


免責聲明!

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



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