1. 程式人生 > 程式設計 >.Net Core 之AutoFac的使用

.Net Core 之AutoFac的使用

目錄
  • Autofac介紹
    • 元件的三種註冊方式
    • 生命週期
  • AutoFac 在asp .net core中的使用

    本文不介紹IoC和DI的概念,如果你對Ioc之前沒有了解的話,建議先去搜索一下相關的資料

    這篇文章將簡單介紹一下AutoFac的基本使用以及在asp .net core中的應用

    Autofac介紹

    元件的三種註冊方式

    1.反射

    2.現成的例項(new)

    3.lambda表示式 (一個執行例項化物件的匿名方法)

    下面是一些簡短的示例,我儘可能多的列出來一些常用的註冊方式,同時在註釋中解釋下“元件”、“服務”等一些名詞的含義

    // 建立註冊元件的builder
    var builder = new ContainerBuilder();
    
    //根據型別註冊元件 ConsoleLogger 暴漏服務:ILogger
    builder.RegisterType<ConsoleLogger>().http://www.cppcns.com
    As<ILogger>(); //根據型別註冊元件 ConsoleLogger,暴漏其實現的所有服務(介面) builder.RegisterType<ConsoleLogger>().AsImplementedInterfaces(); // 根據例項註冊元件 output 暴漏服務:TextWriter var output = new StringWriter(); builder.RegisterInstance(output).As<TextWriter>(); //表示式註冊元件,這裡我們是在建構函式時傳參->"musection" 暴漏服務:IConfigReader builder.Register(c =new ConfigReader("mysection")).As<IConfigReader>(); //表示式註冊元件,解析時傳參 var service = scope.Resolve<IConfigReader>( new NamedParameter("section","mysection")); //反射註冊元件,直接註冊了ConsoleLogger類(必須是具體的類),如果ConsoleLogger有多個建構函式,將會取引數最多的那個建構函式進行例項化 builder.RegisterType<ConsoleLogger>(); //反射註冊元件,手動指定建構函式,這裡指定了呼叫 MyComponent(ILogger log,IConfigReader config)的建構函式進行註冊 builder.RegisterType<MyComponent>() .UsingConstructor(typeof(ILogger),typeof(IConfigReader)); //註冊MySingleton類中的靜態變數"Instance",ExternallyOwned()函式指定自己控制例項的生命週期,而不是由autofac自動釋放 builder.RegisterInstance(MySingleton.Instance).ExternallyOwned(); //一個元件暴漏兩個服務 builder.RegisterType<CallLogger>().As<ILogger>().As<ICallInterceptor>(); //註冊當前程式集中以“Service”結尾的類 builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces(); //註冊"MyApp.Repository"程式集中所有的類 builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfahttp://www.cppcns.com
    ces(); //構建一個容器完成註冊 var rootcontainer = builder.Build(); //可以通過下面這種方式手動獲取IConfigReader 的實現類 //這種手動解析的方式需要 從生命週期作用域內獲取元件,以保證元件最終被釋放 //不要直接從根容器rootcontainer中解析元件,很有可能會導致記憶體洩漏 using(var scope = rootcontainer.BeginLifetimeScope()) { var reader = scope.Resolve<IConfigReader>(); }

    如果不止一個元件暴露了相同的服務,Autofac將使用最後註冊的元件作為服務的提供方。 想要覆蓋這種行為,在註冊程式碼後使用 PreserveExistingDefaults()

    方法修改

    生命週期

    using(var scope = rootcontainer.BeginLifetimeScope())

    上面的這段程式碼建立了一個生命週期作用域

    生命週期作用域是可釋放的,在作用域內解析的元件一定要保證在using之內使用或者最後手動呼叫元件的Dispose()函式

    避免引用類的生命週期大於被引用類的生命週期 :如service 引用 repository 如果service的生命週期為單例,repository的生命週期為perrequest。service不會釋放,所以最終會造成相關的repository始終無法釋放的情況(Captive Dependencies)

    雖然我們需要儘可能的避免直接從根容器解析元件,但總有例外的情況,對於非單例的元件,一定不要忘記呼叫元件的Dispose函式,實際上對於非單例的元件,從專案架構上來說,理論上應該是從建構函式注入進去的而不是手動解析。 需要手動解析的應該為一些配置幫助類等

    對於一個具體元件(類)的生命週期分為以下幾種(後面的函式是autofac對應的函式):

    • 每個依賴一個例項(Instance Per Dependency) (預設) ----InstancePerDependency()
    • 單一例項(Single Instance) 單例 ----SingleInstance()
    • 每個生命週期作用域一個例項(Instance Per Lifetime Scope)----InstancePerLifetimeScope()
    • 每個匹配的生命週期作用域一個例項(Instance Per Matching Lifetime Scope)----InstancePerMatchingLifetimeScope()
    • 每個請求一個例項(Instance Per Request) asp.net web請求----InstancePerRequest()
    • 每次被擁有一個例項(Instance Per Owned) ----InstancePerOwned()

    如果你以前在傳統的ASP.NET MVC專案中用過autofac,需要注意一些區別:

    • .net Core中需要使用InstancePerLifetimeScope替代之前(傳統asp.net)的InstancePerRequest,保證每次HTTP請求只有唯一的依賴例項被建立。InstancePerRequest請求級別已經不存在了
    • .net Core中Web Api與Mvc的註冊方式一樣
    • .net Core中不再需要註冊控制器,控制器由.net core建立,不歸autofac管理(除了控制器的建構函式),這也解釋了為什麼不再使用InstancePerRequest生命週期,但是可以通過AddControllersAsServices()函式改變,想要深入瞭解的可以檢視:https://www.strathweb.com/2016/03/the-subtle-perils-of-controller-dependency-injection-in-asp-net-core-mvc/

    AutoFac 在asp .net core中的使用

    在.net core 中使用autofac還是比較簡單的,相比於傳統的asp.net web 專案,省去了很多步驟

    引入nuget程式包:

    • Autofac
    • Autofac.Extensions.DependencyInjection

    startup 中程式碼:

      public static IContUjcXOhvaDainer AutofacContainer;
        // This method gets called by the runtime. Use this method to 客棧add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            //註冊服務進 IServiceCollection
            services.AddMvc();
            ContainerBuilder builder = new ContainerBuilder();
            //將services中的服務填充到Autofac中.
            builder.Populate(services);
            //新模組元件註冊
            builder.RegisterModule<DefaultModuleRegister>();
            //建立容器.
            AutofacContainer = builder.Build();
            //使用容器建立 AutofacServiceProvider 
            return new AutofacServiceProvider(AutofacContainer);
        }

    上面程式碼呼叫了builder的RegisterModule函式,這個函式需要傳入一個TModule的泛型,稱之為autofac的模組

    模組的功能就是把所有相關的註冊配置都放在一個類中,使程式碼更易於維護和配置,下面展示了DefaultModuleRegister中的程式碼

    DefaultModuleRegister:

    public class DefaultModuleRegister : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            //註冊當前程式集中以“Ser”結尾的類,暴漏類實現的所有介面,生命週期為PerLifetimeScope
            builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Ser")).AsImplementedInterfaces().InstancePerLifetimeScope();
            builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerLifetimeScope();
            //註冊所有"MyApp.Repository"程式集中的類
            //builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfaces();
        }
    
    	public static Assembly GetAssembly(string assemblyName)
        {
            var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(AppContext.BaseDirectory + $"{assemblyName}.dll");
            return assembly;
        }
    }

    Configure函式中可以選擇性的加上程式停止時Autofac的釋放函式:

      public void Configure(IApplicationBuilder app,IHostingEnvironment env,IApplicationLifetime appLifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
    
            app.UseStaticFiles();
    
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",template: "{controller=Home}/{action=Index}/{id?}");
            });
            //程式停止呼叫函式
            appLifetime.ApplicationStopped.Register(() => { AutofacContainer.Dispose(); });
        }

    Controller中程式碼:

      private IUserSer _user;
        private IUserSer _user2;
        public HomeController(IUserSer user,IUserSer user2)
        {
            _user = user;
            _user2 = user2;
        }
        public IActionResult Index()
        {
            using (var scope = Startup.AutofacContainer.BeginLifetimeScope())
            {
                IConfiguration config = scope.Resolve<IConfiguration>();
                IHostingEnvironment env = scope.Resolve<IHostingEnvironment>();
            }
            string name = _user.GetName();
            string name2 = _user2.GetName();
            return View();
        }

    可以看到,因為我們將IServiceCollection中的服務填充到了autofac中了,所以現在可以在任何位置通過AutoFac解析出來.net core預設注入的服務(IConfiguration,IHostingEnvironment等)了

    正常專案使用中,我們應該將AutofacContainer放在一個公共的類庫中以便各個工程均可呼叫

    到此這篇關於.Net Core 之AutoFac的使用的文章就介紹到這了,更多相關.Net Core AutoFac內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!