框架前期准备篇之AutoFac常见用法总结 转载
框架前期準備篇之AutoFac常見用法總結(jié)
?
一. 說在前面的話
凡是大約工作在兩年以上的朋友們,或多或少都會接觸到一些框架搭建方面的知識,只要一談到框架搭建這個問題或者最佳用法這個問題,勢必會引起一點點小小的風波,我說我的好,他說他的好,非常容易罵架,所以在本節(jié)乃至該系列我僅僅是總結(jié)了一下自己日常中的一些用法,談一下自己淺陋的見解,談不上最佳,只要不誤導新手 能有點幫助作用就可以了,如您不喜歡,請“右上角? 謝謝”。
在框架搭建過程中,在層與層的解耦方面,勢必會涉及到IOC框架,.Net 平臺下我用過的IOC框架主要是: Spring.Net 、Unity、AutoFac,當然還有Castle(我沒用過,就不發(fā)表任何評論了), 在用過的IOC框架中,Spring.Net 相對很老了,貌似在2015年就不在更新了,但基本的功能也夠用了。 現(xiàn)階段用的最多的就是Unity和AutoFac了,版本更新也比較快,Unity大約一年前寫過兩篇文章了,本次在該框架系列也會考慮更新一下Unity,本節(jié)主要介紹一下AutoFac的幾個基本用法。
先說一下兩個概念I(lǐng)OC和DI,我的理解:
?、?IOC:調(diào)用者不再創(chuàng)建(不自己new)被調(diào)用者的實例,而是交給容器去創(chuàng)建(AutoFac就充當這里的容器),這就是控制反轉(zhuǎn)。
② DI:容器創(chuàng)建好的實例再注入調(diào)用者的過程,就是依賴注入(比如:屬性注入、構(gòu)造函數(shù)注入等)。
AutoFac的信息:
?、?官網(wǎng)地址:https://autofac.org/
② 官方文檔:http://autofac.readthedocs.io/en/latest/index.html
?、?最新版本:4.8.1 (截止2018-08-21)
本節(jié)的內(nèi)容主要包括:
1. 在使用IOC框架之前的幾種創(chuàng)建對象的方式。
2. AutoFac的基本用法和幾種生命周期。
3. AutoFac和Asp.Net MVC5進行整合,利用屬性的方式進行注入。
事先說明一下本節(jié)要用到的實現(xiàn)類和接口類:
(1). Ypf.BLL層中包括:CatBLL、DogBLL、RoleBLL、UserBLL。
?
1?? public class CatBLL : IAnimalBLL
2???? {
3???????? public string Introduce()
4???????? {
5???????????? return "我是貓";
6???????? }
7???? }
CatBLL
?
1?? public class DogBLL : IAnimalBLL
2???? {
3???????? public string Introduce()
4???????? {
5???????????? return "我是狗";
6???????? }
7???? }
DogBLL
?
?1?? public class RoleBLL : IRoleBLL
?2???? {
?3
?4???????? public IUserBLL userBLL { get; set; }
?5
?6???????? /// <summary>
?7???????? /// 展示角色信息
?8???????? /// </summary>
?9???????? /// <returns></returns>
10???????? public string ShowRoleInfor()
11???????? {
12???????????? return "我是管理員角色";
13???????? }
14
15
16???????? public string ShowDIDemo()
17???????? {
18???????????? return "哈哈:" + userBLL.GetUserInfor();
19???????? }
20
21???? }
RoleBLL
?
?1? public class UserBLL : IUserBLL,IPeopleBLL
?2???? {
?3???????? /// <summary>
?4???????? /// 獲取用戶信息
?5???????? /// </summary>
?6???????? /// <returns></returns>
?7???????? public string GetUserInfor()
?8???????? {
?9???????????? return "我是獲取用戶信息的方法";
10???????? }
11
12???????? /// <summary>
13???????? /// 自我介紹
14???????? /// </summary>
15???????? /// <returns></returns>
16???????? public string Introduce()
17???????? {
18???????????? return "我是ypf";
19???????? }
20???? }
UserBLL
(2). Ypf.IBLL層包括:IAnimalBLL、IPeopleBLL、IRoleBLL、IUserBLL。
?
1? public interface IAnimalBLL
2???? {
3???????? string Introduce();
4???? }
IAnimalBLL
?
1? public interface IPeopleBLL
2???? {
3???????? //自我介紹
4???????? string Introduce();
5???? }
IPeopleBLL
?
1?? public interface IRoleBLL
2???? {
3???????? string ShowRoleInfor();
4
5???????? string ShowDIDemo();
6
7???? }
IRoleBLL
?
1? public interface IUserBLL
2???? {
3???????? string GetUserInfor();
4???? }
IUserBLL
?
二. 引入IOC框架之前的幾個寫法
1.?最原始的方式直接new(需添加對BLL層的引用)
1 {
2??? UserBLL userBll = new UserBLL();
3??? var result1 = userBll.GetUserInfor();
4??? Console.WriteLine(result1);
5 }
?
2. 面向接口編程(仍需添加對BLL層的引用)
1?? {
2????? IUserBLL userBll = new UserBLL();
3????? var result1 = userBll.GetUserInfor();
4????? Console.WriteLine(result1);
5?? }
?
3.?接口+反射(只需將BLL層的程序集拷貝進來)
?1 {
?2?? Assembly ass = Assembly.Load("Ypf.BLL");
?3?? Type type = ass.GetType("Ypf.BLL.UserBLL");
?4?? //調(diào)用默認的無參構(gòu)造函數(shù)進行對象的創(chuàng)建
?5?? object myUserBLL = Activator.CreateInstance(type);
?6?? IUserBLL userBLL = (IUserBLL)myUserBLL;
?7?? var result1 = userBLL.GetUserInfor();
?8?? Console.WriteLine(result1);
?9
10 }
?
4. 手寫IOC(反射+簡單工廠+配置文件)【需將BLL層的程序集拷貝進來】
?配置文件代碼:
? <appSettings>
??? <!--直接修改配置文件,可以切換IUserBLL的實現(xiàn)類,發(fā)布后可以直接通過改配置文件,代碼什么也不用改,體會:反射+面向接口編程-->
??? <add key="DllName" value="Ypf.BLL"/>
??? <add key="ClassName" value="Ypf.BLL.UserBLL"/>
? </appSettings>
簡單工廠代碼:
?1???? /// <summary>
?2???? /// 簡單工廠,隔離對象的創(chuàng)建
?3???? /// </summary>
?4??? public class SimpleFactory
?5???? {
?6???????? private static string DllName = ConfigurationManager.AppSettings["DllName"];
?7???????? private static string ClassName = ConfigurationManager.AppSettings["ClassName"];
?8???????? public static IUserBLL CreateInstance()
?9???????? {
10???????????? Assembly ass = Assembly.Load(DllName);
11???????????? Type type = ass.GetType(ClassName);
12???????????? object obj = Activator.CreateInstance(type);
13???????????? return (IUserBLL)obj;
14???????? }
15???? }
調(diào)用代碼:
1 {
2?????? IUserBLL userBLL = SimpleFactory.CreateInstance();
3?????? var result = userBLL.GetUserInfor();
4?????? Console.WriteLine(result);
5 }
?
三. AutoFac常見用法總結(jié)
1. 基本用法
? 同時添加對Ypf.BLL層和Ypf.IBLL層的引用,然后 聲明容器→注冊實例→解析對象→調(diào)用方法、進行測試,代碼如下:
1? {
2????? ContainerBuilder builder = new ContainerBuilder();
3????? //把UserBLL注冊為IUserBLL實現(xiàn)類,當請求IUserBLL接口的時候,返回UserBLL對象
4????? builder.RegisterType<UserBLL>().As<IUserBLL>();
5????? IContainer resolver = builder.Build();
6????? IUserBLL userBLL = resolver.Resolve<IUserBLL>();
7????? var result1 = userBLL.GetUserInfor();
8????? Console.WriteLine(result1);
9 }
評價:這種用法單純的是為了介紹AutoFac中的幾個方法,僅此而已,在實際開發(fā)沒有這么用的,坑比用法,起不到任何解耦的作用。
?
2.?AsImplementedInterfaces的用法
? 在很多情況下,一個類可能實現(xiàn)了多個接口, 如果我們通過??builder.RegisterType<xxxBLL>().As<IxxxBLL>(); 這種方式按部就班排著把這個類注冊給每個接口,實現(xiàn)幾個接口,就要寫幾行注冊代碼,很繁瑣,我們可以通過?AsImplementedInterfaces()?方法,可以把一個類注冊給它實現(xiàn)的全部接口。
? 這樣的話,想用哪個接口,通過Resolve解析即可,代碼如下:
?1 {
?2????? ContainerBuilder builder = new ContainerBuilder();
?3????? //這樣請求UserBLL實現(xiàn)的任何接口的時候都會返回 UserBLL 對象。
?4????? builder.RegisterType<UserBLL>().AsImplementedInterfaces();
?5????? IContainer resolver = builder.Build();
?6????? IUserBLL iUserBLL = resolver.Resolve<IUserBLL>();
?7????? IPeopleBLL iPeopleBLL = resolver.Resolve<IPeopleBLL>();
?8
?9????? var r1 = iUserBLL.GetUserInfor();
10????? var r2 = iPeopleBLL.Introduce();
11
12????? Console.WriteLine(r1);
13????? Console.WriteLine(r2);
14 }
評價:同時添加對Ypf.BLL層和Ypf.IBLL層的引用,這里也是單純的為了介紹AsImplementedInterfaces()的用法,還是存在實現(xiàn)類的身影,在實際開發(fā)中沒有這么用的,起不到任何解耦的作用,坑比用法。
?
3.?AutoFac+反射(徹底消滅實現(xiàn)類)
引入反射的背景:前面兩種方式都需要添加對Ypf.BLL層的引用,麻煩的要死,根本沒有什么改觀,還是緊耦合在一起。并且如果有很多接口和實現(xiàn)類的話,用RegisterType一行一行的去寫,累個半死,在這種情況下引入反射的概念,簡化代碼量,代碼如下:
?1? {
?2?????? ContainerBuilder builder = new ContainerBuilder();
?3?????? //加載實現(xiàn)類的程序集
?4?????? Assembly asm = Assembly.Load("Ypf.BLL");
?5?????? builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
?6?????? IContainer resolver = builder.Build();
?7
?8?????? IUserBLL userBLL = resolver.Resolve<IUserBLL>();
?9?????? IPeopleBLL peopleBLL = resolver.Resolve<IPeopleBLL>();
10?????? var r1 = userBLL.GetUserInfor();
11?????? var r2 = peopleBLL.Introduce();
12
13?????? Console.WriteLine(r1);
14?????? Console.WriteLine(r2);
15 }
評價:徹底擺脫了實現(xiàn)類的身影,與Ypf.BLL層進行了解耦,只需要添加對Ypf.IBLL層的引用,但需要把Ypf.BLL的程序集拷貝到AutoFacTest項目下。
小小的升級一下:
? 把反射那個程序集類寫到配置文件中,然后在代碼中通過讀取配置文件進行進一步的反射,代碼如下:
1? <appSettings>
2???? <add key="DllName" value="Ypf.BLL"/>
3?? </appSettings>
?1? {
?2????? ContainerBuilder builder = new ContainerBuilder();
?3????? //加載實現(xiàn)類的程序集
?4???? string DllName = ConfigurationManager.AppSettings["DllName"];
?5???? Assembly asm = Assembly.Load(DllName);
?6???? builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
?7???? IContainer resolver = builder.Build();
?8
?9???? IUserBLL userBLL = resolver.Resolve<IUserBLL>();
10???? IPeopleBLL peopleBLL = resolver.Resolve<IPeopleBLL>();
11???? var r1 = userBLL.GetUserInfor();
12???? var r2 = peopleBLL.Introduce();
13
14???? Console.WriteLine(r1);
15???? Console.WriteLine(r2);
16 }
?
4.?PropertiesAutowired(屬性的自動注入)
背景:一個實現(xiàn)類中定義了其他類型的接口屬性,比如RoleBLL中定義IUserBLL的接口屬性,而且要對其進行調(diào)用,?這個時候就需要通過PropertiesAutowired實現(xiàn)屬性的自動注入了。
注:只有通過AutoFac創(chuàng)建的對象才能實現(xiàn)屬性的自動注入!!?相關(guān)的類、接口要是public類型。
?
?1? public class RoleBLL : IRoleBLL
?2???? {
?3
?4???????? public IUserBLL userBLL { get; set; }
?5
?6???????? /// <summary>
?7???????? /// 展示角色信息
?8???????? /// </summary>
?9???????? /// <returns></returns>
10???????? public string ShowRoleInfor()
11???????? {
12???????????? return "我是管理員角色";
13???????? }
14
15
16???????? public string ShowDIDemo()
17???????? {
18???????????? return "哈哈:" + userBLL.GetUserInfor();
19???????? }
20
21
22
23???? }
RoleBLL
?1 {
?2????? ContainerBuilder builder = new ContainerBuilder();
?3????? //加載實現(xiàn)類的程序集
?4????? Assembly asm = Assembly.Load("Ypf.BLL");
?5????? builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
?6????? IContainer resolver = builder.Build();
?7
?8????? IRoleBLL iRoleBLL = resolver.Resolve<IRoleBLL>();
?9????? var r1 = iRoleBLL.ShowDIDemo();
10????? Console.WriteLine(r1);
}
?
下面測試一下不是AutoFac創(chuàng)建的對象能否實現(xiàn)屬性的自動注入,新建TempTest類,在里面聲明IUserBLL屬性,并且在方法中進行調(diào)用,然后new一個TempTest對象,對該showMsg方法進行調(diào)用,發(fā)現(xiàn)報空指針錯誤,說明userBLL屬性為空,沒能自動注入。
1? public class TempTest
2???? {
3???????? public IUserBLL userBLL { get; set; }
4
5???????? public void showMsg()
6???????? {
7???????????? Console.WriteLine(userBLL.GetUserInfor());
8???????? }
9???? }
1 //測試自己new的對象不能實現(xiàn)屬性的自動注入
2 //下面代碼報空指針錯誤
3 {
4????? TempTest t = new TempTest();
5????? t.showMsg();
6 }
?
5.?1個接口多個實現(xiàn)類的情況
背景:1個接口有多個實現(xiàn)類的情況(DogBLL 和 CatBLL 都實現(xiàn)了 IAnimalBLL接口)
分析:resolver.Resolve<IAnimalBLL>();只會返回其中一個類的對象
解決方案:如果想返回多個實現(xiàn)類的對象,改成 resolver.Resolve<IEnumerable<IAnimalBLL>>()即可。
?1???????????? {
?2???????????????? ContainerBuilder builder = new ContainerBuilder();
?3???????????????? //加載實現(xiàn)類的程序集
?4???????????????? Assembly asm = Assembly.Load("Ypf.BLL");
?5???????????????? builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
?6???????????????? IContainer resolver = builder.Build();
?7
?8???????????????? //返回 CalBLL 和 DogBLL 中的一個
?9???????????????? //{
10???????????????? //??? IAnimalBLL iAnimalBLL = resolver.Resolve<IAnimalBLL>();
11???????????????? // ???var r1 = iAnimalBLL.Introduce();
12???????????????? //??? Console.WriteLine(r1);
13???????????????? //}
14
15???????????????? //如何獲取多個呢?
16???????????????? {
17???????????????????? IEnumerable<IAnimalBLL> blls = resolver.Resolve<IEnumerable<IAnimalBLL>>();
18???????????????????? foreach (IAnimalBLL animalBLL in blls)
19???????????????????? {
20???????????????????????? Console.WriteLine(animalBLL.GetType());
21???????????????????????? Console.WriteLine(animalBLL.Introduce());
22???????????????????? }
23???????????????? }
24???????????? }
?
6.?AutoFac的幾種常見生命周期
1. InstancePerDependency:每次請求 Resovle都返回一個新對象。InstancePerDependency()【這也是默認的創(chuàng)建實例的方式。】
2. SingleInstance: 單例,只有在第一次請求的時候創(chuàng)建 。SingleInstance()
3. InstancePerRequest:ASP.Net MVC 專用,每次http請求內(nèi)一個對象(也可以理解為一個方法內(nèi))。InstancePerRequest() 和 CallContext神似
4. InstancePerLifetimeScope:在一個生命周期域中,每一個依賴或調(diào)用創(chuàng)建一個單一的共享的實例,且每一個不同的生命周期域,實例是唯一的,不共享的。
?下面測試一下前兩種生命周期
?情況1
?1?? {
?2???? ContainerBuilder builder = new ContainerBuilder();
?3???? //加載實現(xiàn)類的程序集
?4???? Assembly asm = Assembly.Load("Ypf.BLL");
?5???? builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired().InstancePerDependency();
?6???? IContainer resolver = builder.Build();
?7
?8???? IUserBLL u1 = resolver.Resolve<IUserBLL>();
?9???? IUserBLL u2 = resolver.Resolve<IUserBLL>();
10
11???? Console.WriteLine(object.ReferenceEquals(u1, u2));
12
13? }
結(jié)果:False,證明InstancePerDependency 每次都創(chuàng)建一個新對象
情況2
?1?? {
?2????? ContainerBuilder builder = new ContainerBuilder();
?3????? //加載實現(xiàn)類的程序集
?4????? Assembly asm = Assembly.Load("Ypf.BLL");
?5????? builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired().SingleInstance();
?6????? IContainer resolver = builder.Build();
?7
?8????? IUserBLL u1 = resolver.Resolve<IUserBLL>();
?9????? IUserBLL u2 = resolver.Resolve<IUserBLL>();
10
11????? Console.WriteLine(object.ReferenceEquals(u1, u2));
12
13 }
結(jié)果:true,證明SingleInstance 每次都返回同一個對象。
?
四. AutoFac與MVC整合
1. Controller中通過屬性注入對象
?步驟1:在Ypf.MVC層中添加對Ypf.IBLL層的引用,并將Ypf.BLL的程序集拷貝到 Ypf.MVC中,或者直接改一下Ypf.BLL輸出路徑。
?步驟2:通過Nuget安裝程序集 Autofac.Mvc5。
?步驟3:在Gloabl 注冊 AutoFac代碼。
?1? public class MvcApplication : System.Web.HttpApplication
?2???? {
?3???????? protected void Application_Start()
?4???????? {
?5???????????? AreaRegistration.RegisterAllAreas();
?6???????????? FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
?7???????????? RouteConfig.RegisterRoutes(RouteTable.Routes);
?8???????????? BundleConfig.RegisterBundles(BundleTable.Bundles);
?9
10???????????? /***********下面是AutoFac的注冊*************/
11???????????? //1. 創(chuàng)建容器
12???????????? var builder = new ContainerBuilder();
13???????????? //2. 把當前程序集中的所有Controller都注冊進來
14???????????? builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
15???????????? //3. 把Ypf.BLL中的所有類注冊給它的全部實現(xiàn)接口,并且把實現(xiàn)類中的屬性也進行注冊
16???????????? //{ Assembly asmService = Assembly.Load("Ypf.BLL"); }
17???????????? //PS:這里可以配合配置文件的,將Ypf.BLL寫到配置文件中
18???????????? string DllName = ConfigurationManager.AppSettings["DllName"];
19???????????? Assembly asmService = Assembly.Load(DllName);
20???????????? builder.RegisterAssemblyTypes(asmService).Where(t => !t.IsAbstract).AsImplementedInterfaces().PropertiesAutowired();
21???????????? var container = builder.Build();
22???????????? //4. 下面這句話表示當mvc創(chuàng)建controller對象的時候,都是由AutoFac為我們創(chuàng)建Controller對象
23???????????? DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
24
25
26???????? }
27???? }
?
步驟4:在Controller中進行調(diào)用。
?
2. 普通類中通過代碼獲取對象
在一個沒有通過AutoFac注冊的普通類中如何獲取接口對象呢,通過DependencyResolver.Current.GetService<IUserBLL>();來獲取。
代碼如下:
1?? public class Utils
2???? {
3???????? public static string Test()
4???????? {??????
5???????????? IUserBLL userBLL = DependencyResolver.Current.GetService<IUserBLL>();
6???????????? return userBLL.GetUserInfor();
7???????? }
8???? }
?
3. 如何在普通類中通過屬性的方式注入對象
需要有兩個條件:
?、? 這個普通類的創(chuàng)建必須在Global中通過AutoFac來進行注冊。
?、? 獲取這個類的時候必須通過 DependencyResolver.Current.GetService<IUserBLL>(); 這種方式來獲取。
?在Global文件中注冊該普通類
?
該普通類CommonHelp的獲取必須通過DependencyResolver.Current.GetService<CommonHelp>();方式來獲取。
?
4. 在單獨線程中獲取對象
比如在Quartz.Net 中,需要通過下面代碼來獲取。
?
詳細代碼如下:
?{
??????????????? //1.創(chuàng)建作業(yè)調(diào)度池(Scheduler)
??????????????? IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
?
??????????????? //2.創(chuàng)建一個具體的作業(yè)即job (具體的job需要單獨在一個文件中執(zhí)行)
??????????????? var job = JobBuilder.Create<HelloJob>().Build();
?
??????????????? //3.創(chuàng)建并配置一個觸發(fā)器即trigger?? 1s執(zhí)行一次
??????????????? var trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds(1)
?????????????????????????????????????????????????????????????????????????????? .RepeatForever()).Build();
??????????????? //4.將job和trigger加入到作業(yè)調(diào)度池中
??????????????? scheduler.ScheduleJob(job, trigger);
?
??????????????? //5.開啟調(diào)度
??????????????? scheduler.Start();
}
?1? public class HelloJob:IJob
?2???? {
?3???????? void IJob.Execute(IJobExecutionContext context)
?4???????? {
?5???????????? IUserBLL userBLL;
?6???????????? var container = AutofacDependencyResolver.Current.ApplicationContainer;
?7???????????? using (container.BeginLifetimeScope())
?8???????????? {
?9???????????????? userBLL = container.Resolve<IUserBLL>();
10???????????? }
11???????????? //下面代碼只是測試
12???????????? Console.WriteLine(userBLL.GetUserInfor());
13???????? }
14???? }
?
?
?
?
?
?
?
!
- 作???????者 :?Yaopengfei(姚鵬飛)
- 博客地址 :?http://www.cnblogs.com/yaopengfei/
- 聲?????明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
- 聲?????明2 : 原創(chuàng)博客請在轉(zhuǎn)載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權(quán)利。
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/Jeely/p/11004678.html
總結(jié)
以上是生活随笔為你收集整理的框架前期准备篇之AutoFac常见用法总结 转载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python学习教程:0基础学Pytho
- 下一篇: 效率提升工具Listary