第二节:框架前期准备篇之AutoFac常见用法总结
一. 说在前面的话
本节的内容主要包括:
1. 在使用IOC框架之前的几种创建对象的方式。
2. AutoFac的基本用法和几种生命周期。
3. AutoFac和Asp.Net MVC5进行整合,利用属性的方式进行注入。
事先说明一下本节要用到的实现类和接口类:
(1). Ypf.BLL层中包括:CatBLL、DogBLL、RoleBLL、UserBLL。
public class CatBLL : IAnimalBLL
{
public string Introduce()
{
return "我是猫";
}
}
CatBLL
public class DogBLL : IAnimalBLL
{
public string Introduce()
{
return "我是狗";
}
}
DogBLL
public class RoleBLL : IRoleBLL
{ public IUserBLL userBLL { get; set; } /// <summary>
/// 展示角色信息
/// </summary>
/// <returns></returns>
public string ShowRoleInfor()
{
return "我是管理员角色";
} public string ShowDIDemo()
{
return "哈哈:" + userBLL.GetUserInfor();
} }
RoleBLL
public class UserBLL : IUserBLL,IPeopleBLL
{
/// <summary>
/// 获取用户信息
/// </summary>
/// <returns></returns>
public string GetUserInfor()
{
return "我是获取用户信息的方法";
} /// <summary>
/// 自我介绍
/// </summary>
/// <returns></returns>
public string Introduce()
{
return "我是ypf";
}
}
UserBLL
(2). Ypf.IBLL层包括:IAnimalBLL、IPeopleBLL、IRoleBLL、IUserBLL。
public interface IAnimalBLL
{
string Introduce();
}
IAnimalBLL
public interface IPeopleBLL
{
//自我介绍
string Introduce();
}
IPeopleBLL
public interface IRoleBLL
{
string ShowRoleInfor(); string ShowDIDemo(); }
IRoleBLL
public interface IUserBLL
{
string GetUserInfor();
}
IUserBLL
二. 引入IOC框架之前的几个写法
1. 最原始的方式直接new(需添加对BLL层的引用)
{
UserBLL userBll = new UserBLL();
var result1 = userBll.GetUserInfor();
Console.WriteLine(result1);
}
2. 面向接口编程(仍需添加对BLL层的引用)
{
IUserBLL userBll = new UserBLL();
var result1 = userBll.GetUserInfor();
Console.WriteLine(result1);
}
3. 接口+反射(只需将BLL层的程序集拷贝进来)
{
Assembly ass = Assembly.Load("Ypf.BLL");
Type type = ass.GetType("Ypf.BLL.UserBLL");
//调用默认的无参构造函数进行对象的创建
object myUserBLL = Activator.CreateInstance(type);
IUserBLL userBLL = (IUserBLL)myUserBLL;
var result1 = userBLL.GetUserInfor();
Console.WriteLine(result1);
}
4. 手写IOC(反射+简单工厂+配置文件)【需将BLL层的程序集拷贝进来】
配置文件代码:
<appSettings>
<!--直接修改配置文件,可以切换IUserBLL的实现类,发布后可以直接通过改配置文件,代码什么也不用改,体会:反射+面向接口编程-->
<add key="DllName" value="Ypf.BLL"/>
<add key="ClassName" value="Ypf.BLL.UserBLL"/>
</appSettings>
简单工厂代码:
/// <summary>
/// 简单工厂,隔离对象的创建
/// </summary>
public class SimpleFactory
{
private static string DllName = ConfigurationManager.AppSettings["DllName"];
private static string ClassName = ConfigurationManager.AppSettings["ClassName"];
public static IUserBLL CreateInstance()
{
Assembly ass = Assembly.Load(DllName);
Type type = ass.GetType(ClassName);
object obj = Activator.CreateInstance(type);
return (IUserBLL)obj;
}
}
调用代码:
{
IUserBLL userBLL = SimpleFactory.CreateInstance();
var result = userBLL.GetUserInfor();
Console.WriteLine(result);
}
三. AutoFac常见用法总结
1. 基本用法
同时添加对Ypf.BLL层和Ypf.IBLL层的引用,然后 声明容器→注册实例→解析对象→调用方法、进行测试,代码如下:
{
ContainerBuilder builder = new ContainerBuilder();
//把UserBLL注册为IUserBLL实现类,当请求IUserBLL接口的时候,返回UserBLL对象
builder.RegisterType<UserBLL>().As<IUserBLL>();
IContainer resolver = builder.Build();
IUserBLL userBLL = resolver.Resolve<IUserBLL>();
var result1 = userBLL.GetUserInfor();
Console.WriteLine(result1);
}
评价:这种用法单纯的是为了介绍AutoFac中的几个方法,仅此而已,在实际开发没有这么用的,坑比用法,起不到任何解耦的作用。
2. AsImplementedInterfaces的用法
在很多情况下,一个类可能实现了多个接口, 如果我们通过 builder.RegisterType<xxxBLL>().As<IxxxBLL>(); 这种方式按部就班排着把这个类注册给每个接口,实现几个接口,就要写几行注册代码,很繁琐,我们可以通过 AsImplementedInterfaces() 方法,可以把一个类注册给它实现的全部接口。
这样的话,想用哪个接口,通过Resolve解析即可,代码如下:
{
ContainerBuilder builder = new ContainerBuilder();
//这样请求UserBLL实现的任何接口的时候都会返回 UserBLL 对象。
builder.RegisterType<UserBLL>().AsImplementedInterfaces();
IContainer resolver = builder.Build();
IUserBLL iUserBLL = resolver.Resolve<IUserBLL>();
IPeopleBLL iPeopleBLL = resolver.Resolve<IPeopleBLL>();
var r1 = iUserBLL.GetUserInfor();
var r2 = iPeopleBLL.Introduce();
Console.WriteLine(r1);
Console.WriteLine(r2);
}
评价:同时添加对Ypf.BLL层和Ypf.IBLL层的引用,这里也是单纯的为了介绍AsImplementedInterfaces()的用法,还是存在实现类的身影,在实际开发中没有这么用的,起不到任何解耦的作用,坑比用法。
3. AutoFac+反射(彻底消灭实现类)
引入反射的背景:前面两种方式都需要添加对Ypf.BLL层的引用,麻烦的要死,根本没有什么改观,还是紧耦合在一起。并且如果有很多接口和实现类的话,用RegisterType一行一行的去写,累个半死,在这种情况下引入反射的概念,简化代码量,代码如下:
{
ContainerBuilder builder = new ContainerBuilder();
//加载实现类的程序集
Assembly asm = Assembly.Load("Ypf.BLL");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
IContainer resolver = builder.Build();
IUserBLL userBLL = resolver.Resolve<IUserBLL>();
IPeopleBLL peopleBLL = resolver.Resolve<IPeopleBLL>();
var r1 = userBLL.GetUserInfor();
var r2 = peopleBLL.Introduce();
Console.WriteLine(r1);
Console.WriteLine(r2);
}
评价:彻底摆脱了实现类的身影,与Ypf.BLL层进行了解耦,只需要添加对Ypf.IBLL层的引用,但需要把Ypf.BLL的程序集拷贝到AutoFacTest项目下。
小小的升级一下:
把反射那个程序集类写到配置文件中,然后在代码中通过读取配置文件进行进一步的反射,代码如下:
<appSettings>
<add key="DllName" value="Ypf.BLL"/>
</appSettings>
{
ContainerBuilder builder = new ContainerBuilder();
//加载实现类的程序集
string DllName = ConfigurationManager.AppSettings["DllName"];
Assembly asm = Assembly.Load(DllName);
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces();
IContainer resolver = builder.Build();
IUserBLL userBLL = resolver.Resolve<IUserBLL>();
IPeopleBLL peopleBLL = resolver.Resolve<IPeopleBLL>();
var r1 = userBLL.GetUserInfor();
var r2 = peopleBLL.Introduce();
Console.WriteLine(r1);
Console.WriteLine(r2);
}
4. PropertiesAutowired(属性的自动注入)
背景:一个实现类中定义了其他类型的接口属性,比如RoleBLL中定义IUserBLL的接口属性,而且要对其进行调用, 这个时候就需要通过PropertiesAutowired实现属性的自动注入了。
注:只有通过AutoFac创建的对象才能实现属性的自动注入!! 相关的类、接口要是public类型。
public class RoleBLL : IRoleBLL
{ public IUserBLL userBLL { get; set; } /// <summary>
/// 展示角色信息
/// </summary>
/// <returns></returns>
public string ShowRoleInfor()
{
return "我是管理员角色";
} public string ShowDIDemo()
{
return "哈哈:" + userBLL.GetUserInfor();
} }
RoleBLL
{
ContainerBuilder builder = new ContainerBuilder();
//加载实现类的程序集
Assembly asm = Assembly.Load("Ypf.BLL");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
IContainer resolver = builder.Build();
IRoleBLL iRoleBLL = resolver.Resolve<IRoleBLL>();
var r1 = iRoleBLL.ShowDIDemo();
Console.WriteLine(r1);
}

下面测试一下不是AutoFac创建的对象能否实现属性的自动注入,新建TempTest类,在里面声明IUserBLL属性,并且在方法中进行调用,然后new一个TempTest对象,对该showMsg方法进行调用,发现报空指针错误,说明userBLL属性为空,没能自动注入。
public class TempTest
{
public IUserBLL userBLL { get; set; } public void showMsg()
{
Console.WriteLine(userBLL.GetUserInfor());
}
}
//测试自己new的对象不能实现属性的自动注入
//下面代码报空指针错误
{
TempTest t = new TempTest();
t.showMsg();
}
5. 1个接口多个实现类的情况
背景:1个接口有多个实现类的情况(DogBLL 和 CatBLL 都实现了 IAnimalBLL接口)
分析:resolver.Resolve<IAnimalBLL>();只会返回其中一个类的对象
解决方案:如果想返回多个实现类的对象,改成 resolver.Resolve<IEnumerable<IAnimalBLL>>()即可。
{
ContainerBuilder builder = new ContainerBuilder();
//加载实现类的程序集
Assembly asm = Assembly.Load("Ypf.BLL");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired();
IContainer resolver = builder.Build();
//返回 CalBLL 和 DogBLL 中的一个
//{
// IAnimalBLL iAnimalBLL = resolver.Resolve<IAnimalBLL>();
// var r1 = iAnimalBLL.Introduce();
// Console.WriteLine(r1);
//}
//如何获取多个呢?
{
IEnumerable<IAnimalBLL> blls = resolver.Resolve<IEnumerable<IAnimalBLL>>();
foreach (IAnimalBLL animalBLL in blls)
{
Console.WriteLine(animalBLL.GetType());
Console.WriteLine(animalBLL.Introduce());
}
}
}
6. AutoFac的几种常见生命周期
1. InstancePerDependency:每次请求 Resovle都返回一个新对象。InstancePerDependency()【这也是默认的创建实例的方式。】
2. SingleInstance: 单例,只有在第一次请求的时候创建 。SingleInstance()
3. InstancePerRequest:ASP.Net MVC 专用,每次http请求内一个对象(也可以理解为一个方法内)。InstancePerRequest() 和 CallContext神似
4. InstancePerLifetimeScope:在一个生命周期域中,每一个依赖或调用创建一个单一的共享的实例,且每一个不同的生命周期域,实例是唯一的,不共享的。
下面测试一下前两种生命周期
情况1
{
ContainerBuilder builder = new ContainerBuilder();
//加载实现类的程序集
Assembly asm = Assembly.Load("Ypf.BLL");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired().InstancePerDependency();
IContainer resolver = builder.Build();
IUserBLL u1 = resolver.Resolve<IUserBLL>();
IUserBLL u2 = resolver.Resolve<IUserBLL>();
Console.WriteLine(object.ReferenceEquals(u1, u2));
}
结果:False,证明InstancePerDependency 每次都创建一个新对象
情况2
{
ContainerBuilder builder = new ContainerBuilder();
//加载实现类的程序集
Assembly asm = Assembly.Load("Ypf.BLL");
builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().PropertiesAutowired().SingleInstance();
IContainer resolver = builder.Build();
IUserBLL u1 = resolver.Resolve<IUserBLL>();
IUserBLL u2 = resolver.Resolve<IUserBLL>();
Console.WriteLine(object.ReferenceEquals(u1, u2));
}
结果:true,证明SingleInstance 每次都返回同一个对象。
四. AutoFac与MVC整合
1. Controller中通过属性注入对象
步骤1:在Ypf.MVC层中添加对Ypf.IBLL层的引用,并将Ypf.BLL的程序集拷贝到 Ypf.MVC中,或者直接改一下Ypf.BLL输出路径。
步骤2:通过Nuget安装程序集 Autofac.Mvc5。
步骤3:在Gloabl 注册 AutoFac代码。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); /***********下面是AutoFac的注册*************/
//1. 创建容器
var builder = new ContainerBuilder();
//2. 把当前程序集中的所有Controller都注册进来
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
//3. 把Ypf.BLL中的所有类注册给它的全部实现接口,并且把实现类中的属性也进行注册
//{ Assembly asmService = Assembly.Load("Ypf.BLL"); }
//PS:这里可以配合配置文件的,将Ypf.BLL写到配置文件中
string DllName = ConfigurationManager.AppSettings["DllName"];
Assembly asmService = Assembly.Load(DllName);
builder.RegisterAssemblyTypes(asmService).Where(t => !t.IsAbstract).AsImplementedInterfaces().PropertiesAutowired();
var container = builder.Build();
//4. 下面这句话表示当mvc创建controller对象的时候,都是由AutoFac为我们创建Controller对象
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); }
}

PS:分享个小技巧

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

2. 普通类中通过代码获取对象
在一个没有通过AutoFac注册的普通类中如何获取接口对象呢,通过DependencyResolver.Current.GetService<IUserBLL>();来获取。
代码如下:
public class Utils
{
public static string Test()
{
IUserBLL userBLL = DependencyResolver.Current.GetService<IUserBLL>();
return userBLL.GetUserInfor();
}
}
3. 如何在普通类中通过属性的方式注入对象
需要有两个条件:
①: 这个普通类的创建必须在Global中通过AutoFac来进行注册。
②: 获取这个类的时候必须通过 DependencyResolver.Current.GetService<IUserBLL>(); 这种方式来获取。
在Global文件中注册该普通类

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

4. 在单独线程中获取对象
比如在Quartz.Net 中,需要通过下面代码来获取。

详细代码如下:
{
//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()
.RepeatForever()).Build();
//4.将job和trigger加入到作业调度池中
scheduler.ScheduleJob(job, trigger);
//5.开启调度
scheduler.Start();
}
public class HelloJob:IJob
{
void IJob.Execute(IJobExecutionContext context)
{
IUserBLL userBLL;
var container = AutofacDependencyResolver.Current.ApplicationContainer;
using (container.BeginLifetimeScope())
{
userBLL = container.Resolve<IUserBLL>();
}
//下面代码只是测试
Console.WriteLine(userBLL.GetUserInfor());
}
}
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
第二节:框架前期准备篇之AutoFac常见用法总结的更多相关文章
- 框架前期准备篇之AutoFac常见用法总结 转载
框架前期准备篇之AutoFac常见用法总结 一. 说在前面的话 凡是大约工作在两年以上的朋友们,或多或少都会接触到一些框架搭建方面的知识,只要一谈到框架搭建这个问题或者最佳用法这个问题,势必会引起一点 ...
- 转载 AutoFac常见用法总结
第二节:框架前期准备篇之AutoFac常见用法总结 一. 说在前面的话 凡是大约工作在两年以上的朋友们,或多或少都会接触到一些框架搭建方面的知识,只要一谈到框架搭建这个问题或者最佳用法这个问题,势 ...
- iOS 开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- iOS开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- 第一节:框架前期准备篇之Log4Net日志详解
一. Log4Net简介 Log4net是从Java中的Log4j迁移过来的一个.Net版的开源日志框架,它的功能很强大,可以将日志分为不同的等级,以不同的格式输出到不同的存储介质中,比如:数据库.t ...
- 第四节:框架前期准备篇之进程外Session的两种配置方式
一. 基本介绍 1. 背景:Asp.Net默认的Session机制是进程内,存储在服务器端内存中,有这么几个缺点: ①:既然存在内存中,空间有限,不能存储大数据量信息,数据量多的话Session会被挤 ...
- 第三节:框架前期准备篇之利用Newtonsoft.Json改造MVC默认的JsonResult
一. 背景 在MVC框架中,我们可能经常会用到 return Json(),而Json方法内部又是一个JsonResult类,那么JsonResult内部又是什么原理呢?在MVC框架中,各种xxxRe ...
- 自学HTML5第二节(标签篇---新增标签详解)
HTML5新增标签: <article> 标签 规定独立的自包含内容.一篇文章应有其自身的意义,应该有可能独立于站点的其余部分对其进行分发. <article> 元素的潜在来源 ...
- iOS开发多线程篇 — GCD的常见用法
一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) withObject:nil ...
随机推荐
- 固态+机械双硬盘分别安装Win10和Ubuntu16.04双系统
博主的笔记本是256G固态+1T机械,固态事先已经安装好了Win10系统,想着把机械硬盘分出500G用来安装Ubuntu16.04,剩余的继续用作Win下的资料盘.这里不介绍安装Win10过程,也不记 ...
- java格式化
http://tool.oschina.net/apidocs/apidoc?api=jdk-zh https://www.jianshu.com/p/c8f16cab35e1# 参考官方的 api说 ...
- 数据库连接池性能比对(hikari druid c3p0 dbcp jdbc)
https://blog.csdn.net/qq_31125793/article/details/51241943 背景 对现有的数据库连接池做调研对比,综合性能,可靠性,稳定性,扩展性等因素选出推 ...
- Taro文件上传:Blob Url下载Blob对象本身并通过接口上传到服务器
最近项目的文件上传遇到一个问题,就是Taro的chooseImage传给回调的是一个Blob对象,一般来说,上传控件都会导出Data Url,而Taro给了一个Blob Url,问题在于,我直接令im ...
- Node+express实现后台服务接口
一.准备工作 创建代码目录,依次执行以下操作 1.(若没有安装过)安装node 2.npm init(package.json) 3.安装express(请求)npm install express ...
- 工具篇-Spring boot JPA多数据源
写这篇博文是因为这个东西坑太多,首先说明下边实现的多数据源不是动态切换的,应该算是静态的. 坑一.pom文件 pom中spring boot以及mysql connector的版本一定要注意. < ...
- Spring的事件机制详解
同步事件和异步事件 同步事件:在一个线程里,按顺序执行业务,做完一件事再去做下一件事. 异步事件:在一个线程里,做一个事的同事,可以另起一个新的线程执行另一件事,这样两件事可以同时执行. 用一个例子来 ...
- .net core 的图片处理及二维码的生成及解析
写代码这事,掐指算来已经十有余年. 从html到css到javascript到vbscript到c#,从兴趣到职业,生活总是失落与惊喜并存. 绝大部分时候,出发并不是因为知道该到哪里去,只是知道不能再 ...
- 在 .NET Core 中结合 HttpClientFactory 使用 Polly(下篇)
译者:王亮作者:Polly 团队原文:http://t.cn/EhZ90oq声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的(包括标题).其中可能会去除一些不影响理解但本人实在不知道如 ...
- 开发工具IntelliJ IDEA的安装步骤及首次启动和创建项目
开发工具IDEA概述 DEA是一个专门针对Java的集成开发工具(IDE),由Java语言编写.所以,需要有JRE运行环境并配置好环境变量.它可以极大地提升我们的开发效率.可以自动编译,检查错误.在公 ...