AutoFac常见用法总结

1. 基本用法

   同时添加对Ypf.BLL层和Ypf.IBLL层的引用,然后 声明容器→注册实例→解析对象→调用方法、进行测试,代码如下:

复制代码

1  {2      ContainerBuilder builder = new ContainerBuilder();3      //把UserBLL注册为IUserBLL实现类,当请求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中的几个方法,仅此而已,在实际开发没有这么用的,坑比用法,起不到任何解耦的作用。

 

2. AsImplementedInterfaces的用法

   在很多情况下,一个类可能实现了多个接口, 如果我们通过  builder.RegisterType<xxxBLL>().As<IxxxBLL>(); 这种方式按部就班排着把这个类注册给每个接口,实现几个接口,就要写几行注册代码,很繁琐,我们可以通过 AsImplementedInterfaces() 方法,可以把一个类注册给它实现的全部接口。

   这样的话,想用哪个接口,通过Resolve解析即可,代码如下:

复制代码

 1 { 2      ContainerBuilder builder = new ContainerBuilder(); 3      //这样请求UserBLL实现的任何接口的时候都会返回 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()的用法,还是存在实现类的身影,在实际开发中没有这么用的,起不到任何解耦的作用,坑比用法。

 

3. AutoFac+反射(彻底消灭实现类)

  引入反射的背景:前面两种方式都需要添加对Ypf.BLL层的引用,麻烦的要死,根本没有什么改观,还是紧耦合在一起。并且如果有很多接口和实现类的话,用RegisterType一行一行的去写,累个半死,在这种情况下引入反射的概念,简化代码量,代码如下:

复制代码

 1  { 2       ContainerBuilder builder = new ContainerBuilder(); 3       //加载实现类的程序集 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 }

复制代码

  评价:彻底摆脱了实现类的身影,与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      //加载实现类的程序集 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(属性的自动注入)

  背景:一个实现类中定义了其他类型的接口属性,比如RoleBLL中定义IUserBLL的接口属性,而且要对其进行调用, 这个时候就需要通过PropertiesAutowired实现属性的自动注入了。

  注:只有通过AutoFac创建的对象才能实现属性的自动注入!! 相关的类、接口要是public类型。

AutoFac常见用法总结RoleBLL

复制代码

 1 { 2      ContainerBuilder builder = new ContainerBuilder(); 3      //加载实现类的程序集 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常见用法总结

  下面测试一下不是AutoFac创建的对象能否实现属性的自动注入,新建TempTest类,在里面声明IUserBLL属性,并且在方法中进行调用,然后new一个TempTest对象,对该showMsg方法进行调用,发现报空指针错误,说明userBLL属性为空,没能自动注入。

复制代码

1  public class TempTest2     {3         public IUserBLL userBLL { get; set; }4 5         public void showMsg()6         {7             Console.WriteLine(userBLL.GetUserInfor());8         }9     }

复制代码

1 //测试自己new的对象不能实现属性的自动注入2 //下面代码报空指针错误3 {4      TempTest t = new TempTest();5      t.showMsg();6 }

 

5. 1个接口多个实现类的情况

  背景:1个接口有多个实现类的情况(DogBLL 和 CatBLL 都实现了 IAnimalBLL接口)

  分析:resolver.Resolve<IAnimalBLL>();只会返回其中一个类的对象

  解决方案:如果想返回多个实现类的对象,改成 resolver.Resolve<IEnumerable<IAnimalBLL>>()即可。

复制代码

 1             { 2                 ContainerBuilder builder = new ContainerBuilder(); 3                 //加载实现类的程序集 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()【这也是默认的创建实例的方式。】

2. SingleInstance: 单例,只有在第一次请求的时候创建 。SingleInstance()

3. InstancePerRequest:ASP.Net MVC 专用,每次http请求内一个对象(也可以理解为一个方法内)。InstancePerRequest() 和 CallContext神似

4. InstancePerLifetimeScope:在一个生命周期域中,每一个依赖或调用创建一个单一的共享的实例,且每一个不同的生命周期域,实例是唯一的,不共享的。

 下面测试一下前两种生命周期

 情况1

复制代码

 1   { 2     ContainerBuilder builder = new ContainerBuilder(); 3     //加载实现类的程序集 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  }

复制代码

结果:False,证明InstancePerDependency 每次都创建一个新对象

情况2

复制代码

 1   { 2      ContainerBuilder builder = new ContainerBuilder(); 3      //加载实现类的程序集 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 }

复制代码

结果: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. 创建容器12             var builder = new ContainerBuilder();13             //2. 把当前程序集中的所有Controller都注册进来14             builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();15             //3. 把Ypf.BLL中的所有类注册给它的全部实现接口,并且把实现类中的属性也进行注册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创建controller对象的时候,都是由AutoFac为我们创建Controller对象23             DependencyResolver.SetResolver(new AutofacDependencyResolver(container));24 25 26         }27     }

复制代码

AutoFac常见用法总结

PS:分享个小技巧

AutoFac常见用法总结

步骤4:在Controller中进行调用。

 AutoFac常见用法总结

2. 普通类中通过代码获取对象

  在一个没有通过AutoFac注册的普通类中如何获取接口对象呢,通过DependencyResolver.Current.GetService<IUserBLL>();来获取。

  代码如下:

复制代码

1   public class Utils2     {3         public static string Test()4         {       
5             IUserBLL userBLL = DependencyResolver.Current.GetService<IUserBLL>();6             return userBLL.GetUserInfor();7         }8     }

复制代码

 

3. 如何在普通类中通过属性的方式注入对象

需要有两个条件:

  ①: 这个普通类的创建必须在Global中通过AutoFac来进行注册。

  ②: 获取这个类的时候必须通过 DependencyResolver.Current.GetService<IUserBLL>(); 这种方式来获取。

 在Global文件中注册该普通类

 AutoFac常见用法总结

该普通类CommonHelp的获取必须通过DependencyResolver.Current.GetService<CommonHelp>();方式来获取。

 AutoFac常见用法总结

4. 在单独线程中获取对象

  比如在Quartz.Net 中,需要通过下面代码来获取。

AutoFac常见用法总结

详细代码如下:

复制代码

 {                //1.创建作业调度池(Scheduler)
                IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();                //2.创建一个具体的作业即job (具体的job需要单独在一个文件中执行)
                var job = JobBuilder.Create<HelloJob>().Build();                //3.创建并配置一个触发器即trigger   1s执行一次
                var trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds(1)
                                                                               .RepeatForever()).Build();                //4.将job和trigger加入到作业调度池中                scheduler.ScheduleJob(job, trigger);                //5.开启调度                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     }

复制代码