ASP.NET IOC之 AutoFac的认识和结合MVC的使用
2016-06-16 15:27 yebo750 阅读(215) 评论(0) 编辑 收藏 举报这几天研究了解发现AutoFac是个牛X的IOC容器,是.NET领域比较流行的IOC框架之一,传说是速度最快的,~ 据相关资料,相关学习,和认知,遂做了一些整理
优点:
它是C#语言联系很紧密,也就是说C#里的很多编程方式都可以为Autofac使用,例如可以用Lambda表达式注册组件
较低的学习曲线,学习它非常的简单,只要你理解了IoC和DI的概念以及在何时需要使用它们
XML配置支持
自动装配
与Asp.Net MVC 集成
微软的Orchad开源程序使用的就是Autofac,从该源码可以看出它的方便和强大
还有相关介绍:http://www.oschina.net/p/autofac
有博友做了相关测试:http://www.cnblogs.com/liping13599168/archive/2011/07/17/2108734.html
所以墙裂推荐用他作为IOC的终极解决方案!
一、AutoFac的简单使用,第二点介绍在MVC中的使用
将Autofac整合到你的应用的基本模式如下:
- 按照控制反转(IoC)的思想构建你的应用程序
- 添加Autofac引用
- 在application启动代码里创建
ContainerBuilder
对象 - 注册组件
- Build容器并且保存以备用
- 在程序执行阶段
- 从容器创建一个作用域
- 在作用域里获取组件的实例
首先获取AutoFac,这里你可以通过各种方式下载,刚开始我找的各种地址都失效了,有的也没更新,各种不靠谱,
推荐直接用VS中的NuGet来加载AutoFac,(路径:工具——NuGet包管理器——管理解决方案的NuGet的程序包——搜索框输入AutoFac即可,ps搜索框上面得是浏览)
不论是哪种方式,最终的目的就是将 Autofac.dll,Autofac.Configuration.dll 这两个程序集引用到你的项目中。
这样在你的项目中,如果想使用AutoFac,只需添加其命名空间引用即可~
控制反转的思想是,在类的构造函数里传递依赖而不是在应用程序里将这些类绑在一起让类自己创建他们的依赖。关于依赖注入
http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html 这里有一个很形象的例子。如果感兴趣可以去了解一下。
1、新建项目,引入DLL或者通过NuGet安装,然后定义一个数据访问的接口:
// 这个接口帮助我们从Console 解耦"输出"方法 // 我们不需要关心怎样输出,只要知道能输出即可 public interface IDAL { void Insert(string commandText); }
2、用Sql和Oracle两种方式分别实现以上接口(仅演示,不是真的实现数据交互)
// 这里IDAL接口的实现完成向控制台的输出。 public class SqlDAL : IDAL { public void Insert(string commandText) { Console.WriteLine("使用sql添加相关信息"); } } public class OracleDAL : IDAL { public void Insert(string commandText) { Console.WriteLine("使用Oracle添加相关信息"); } }
3、实现构造函数依赖
// DBManager 对上述接口依赖 // 注意这里的构造函数参数是IDAL 类型 // 这样这个Add 的Insert方法由IDAL 的实现决定 public class DBManager { IDAL _dal; public DBManager(IDAL dal) { _dal= dal; } public void Add(string commandText) { _dal.Insert(commandText); } }
4、AtuoFac的使用
说明: 在应用程序启动过程中,首先要创建一个ContainerBuilder
并且用它注册你的组件。组件是一个表达式, .NET类型或者其他的一段暴露一个或者多个服务的代码并且可以用在其他的依赖里。
简单来说,就像下面的例子所述,定义一个实现某个接口的.NET类型
public class SomeType : IService { }
你可以通过下面两种方法之一来定位这个类型
- 指定类型本身,SomeType
- 指定接口,一个IService
在这个例子里,这个组件是SomeType
,他暴露的服务是SomeType
和IService
.
在Autofac里,你应当用一个ContainerBuilder
来注册他们,如下:
static void Main(string[] args) { // 创建你的builder var builder = new ContainerBuilder(); //注册DBManager,当注册的类型在相应得到的容器中可以Resolve(解析)DBManager实例。 builder.RegisterType<DBManager>(); // 注册类型及其实例。例如下面就是注册接口IDAL的实例OracleDAL,通过AS可以让DBManager类中通过构造函数依赖注入类型相应的接口。 builder.RegisterType<OracleDAL>().As<IDAL>(); builder.RegisterType<SqlDAL>().As<IDAL>(); // 创建作用域,Build()方法生成一个对应的Container实例使用,然后释放 using (var container = builder.Build()) { //通过Resolve解析到注册的类型实例。 var manager = container.Resolve<DBManager>(); manager.Add("INSERT INTO Persons VALUES ('Man', '25', 'WangW', 'Shanghai')"); } Console.ReadKey(); }
当你运行你的程序时…
- Add()方法要求Autofac创建了一个DBManager对象
- Autofac发现DBManager构造函数需要IDAL
- Autofac发现IDAL 映射到SqlDAL,所以创建一个新的SqlDAL的实例
- Autofac使用SqlDAL实例完成IDAL 的创建
- Autofac返回一个完整的DBManager对象给”Add()”来消费
输出结果:“使用sql添加相关信息”,
如果希望输出不同的内容,改变一下注册过程即可实现控制反转了
输出:"使用Oracle添加相关信息"
这是比较简单的使用方式,如果复杂点,可以看看这篇
http://www.cnblogs.com/liping13599168/archive/2011/07/16/2108209.html
二、AtuoFac AtuoFac在ASP.NET MVC中的应用
1、首先在函数Application_Start() 注册自己的控制器类,一定要引入Autofac.Integration.Mvc.dll
1 using System; 2 using System.Reflection; 3 using System.Web; 4 using System.Web.Mvc; 5 using System.Web.Routing; 6 using System.Web.Optimization; 7 using Autofac; 8 using Autofac.Integration.Mvc; 9 using AutofacDemo.Models; 10 11 namespace AutofacDemo 12 { 13 public class MvcApplication : System.Web.HttpApplication 14 { 15 protected void Application_Start() 16 { 17 //依赖注入开始 18 var builder = new ContainerBuilder(); 19 builder.RegisterType<StudentRepository>().As<IStudentRepository>();//注册类型及其实例 20 builder.RegisterControllers(Assembly.GetExecutingAssembly());//注册当前程序集内所有的Controller类。 21 //// builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();//注册当前程序集内的所有类 22 var container = builder.Build(); 23 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 24 25 //MVC用到的 26 AreaRegistration.RegisterAllAreas(); 27 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 28 RouteConfig.RegisterRoutes(RouteTable.Routes); 29 BundleConfig.RegisterBundles(BundleTable.Bundles);
30 } 31 } 32 }
2、首先声明一个Student学生类,接口以及实现
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 namespace AutofacDemo.Models 6 { 7 public class Student 8 { 9 public int Id { get; set; } 10 public string Name { get; set; } 11 public string Graduation { get; set; } 12 public string School { get; set; } 13 public string Major { get; set; } 14 } 15 16 ///声明仓储接口仓储接口及其实现 17 public interface IStudentRepository 18 { 19 IEnumerable<Student> GetAll(); 20 Student Get(int id); 21 Student Add(Student item); 22 bool Update(Student item); 23 bool Delete(int id); 24 } 25 public class StudentRepository : IStudentRepository 26 { 27 private List<Student> Articles = new List<Student>(); 28 29 public StudentRepository() 30 { 31 //添加演示数据 32 Add(new Student { Id = 1, Name = "张三", Major = "软件工程", Graduation = "2013年", School = "西安工业大学" }); 33 Add(new Student { Id = 2, Name = "李四", Major = "计算机科学与技术", Graduation = "2013年", School = "西安工业大学" }); 34 Add(new Student { Id = 3, Name = "王五", Major = "自动化", Graduation = "2013年", School = "西安工业大学" }); 35 } 36 /// <summary> 37 /// 获取全部学生信息 38 /// </summary> 39 /// <returns></returns> 40 public IEnumerable<Student> GetAll() 41 { 42 return Articles; 43 } 44 /// <summary> 45 /// 通过ID获取学生信息 46 /// </summary> 47 /// <param name="id"></param> 48 /// <returns></returns> 49 public Student Get(int id) 50 { 51 return Articles.Find(p => p.Id == id); 52 } 53 /// <summary> 54 /// 添加学生信息 55 /// </summary> 56 /// <param name="item"></param> 57 /// <returns></returns> 58 public Student Add(Student item) 59 { 60 if (item == null) 61 { 62 throw new ArgumentNullException("item"); 63 } 64 Articles.Add(item); 65 return item; 66 } 67 /// <summary> 68 /// 更新学生信息 69 /// </summary> 70 /// <param name="item"></param> 71 /// <returns></returns> 72 public bool Update(Student item) 73 { 74 if (item == null) 75 { 76 throw new ArgumentNullException("item"); 77 } 78 79 int index = Articles.FindIndex(p => p.Id == item.Id); 80 if (index == -1) 81 { 82 return false; 83 } 84 Articles.RemoveAt(index); 85 Articles.Add(item); 86 return true; 87 } 88 /// <summary> 89 /// 删除学生信息 90 /// </summary> 91 /// <param name="id"></param> 92 /// <returns></returns> 93 public bool Delete(int id) 94 { 95 Articles.RemoveAll(p => p.Id == id); 96 return true; 97 } 98 } 99 }
3、添加控制器StudentController,并注入依赖代码
1 public class StudentController : Controller 2 { 3 readonly IStudentRepository _repository; 4 5 //构造器注入 6 public StudentController(IStudentRepository repository) 7 { 8 this._repository = repository; 9 } 10 11 // GET: Student 12 public ActionResult Index() 13 { 14 var data = _repository.GetAll(); 15 return View(data); 16 } 17 }
4、为控制器StudentController的Index方法添加视图
1 @{ 2 ViewBag.Title = "Index"; 3 } 4 5 <h2>Index</h2> 6 7 @model List<AutofacDemo.Models.Student> 8 <table id="datatable" cellpadding="0" cellspacing="0"> 9 <thead class="gray_d"> 10 <tr> 11 <td class="sth" style="width:3%;">序号</td> 12 <td class="sth" style="width:4%;">姓名</td> 13 <td class="sth" style="width:4%;">专业</td> 14 <td class="sth" style="width:4%;">日期</td> 15 <td class="sth" style="width:4%;">学校</td> 16 </tr> 17 </thead> 18 <tbody> 19 @foreach (var item in Model) 20 { 21 <tr target="sid_user" rel="@Html.DisplayFor(modelItem => item.Id)"> 22 <td> @Html.DisplayFor(modelItem => item.Id) </td> 23 <td> @Html.DisplayFor(modelItem => item.Name) </td> 24 <td> @Html.DisplayFor(modelItem => item.Major) </td> 25 <td> @Html.DisplayFor(modelItem => item.Graduation) </td> 26 <td> @Html.DisplayFor(modelItem => item.School) </td> 27 <td> 28 </tr> 29 } 30 </tbody> 31 </table>
三、关于AutoFac的一些常用方法说明
1、builder.RegisterType<Object>().As<Iobject>():
//注册类型及其实例。例如下面就是注册接口IDAL的实例SqlDAL ContainerBuilder builder = new ContainerBuilder(); builder.RegisterType<SqlDAL>().As<IDAL>(); IContainer container = builder.Build(); SqlDAL sqlDAL = (SqlDAL)container.Resolve<IDAL>(); 2、IContainer.Resolve<IDAL>()://解析某个接口的实例。例如上面的最后一行代码就是解析IDAL的实例SqlDAL 3、builder.RegisterType<Object>().Named<Iobject>(string name): //为一个接口注册不同的实例。有时候难免会碰到多个类映射同一个接口, //比如SqlDAL和OracleDAL都实现了IDAL接口,为了准确获取想要的类型,就必须在注册时起名字。
builder.RegisterType<SqlDAL>().Named<IDAL>("sql"); builder.RegisterType<OracleDAL>().Named<IDAL>("oracle"); IContainer container = builder.Build(); SqlDAL sqlDAL = (SqlDAL)container.ResolveNamed<IDAL>("sql"); OracleDAL oracleDAL = (OracleDAL)container.ResolveNamed<IDAL>("oracle"); 4、IContainer.ResolveNamed<IDAL>(string name)://解析某个接口的“命名实例”。例如上面的最后一行代码就是解析IDAL的命名实例OracleDAL 5、builder.RegisterType<Object>().Keyed<Iobject>(Enum enum)://以枚举的方式为一个接口注册不同的实例。
//有时候我们会将某一个接口的不同实现用枚举来区分,而不是字符串,例如: public enum DBType{ Sql, Oracle} builder.RegisterType<SqlDAL>().Keyed<IDAL>(DBType.Sql); builder.RegisterType<OracleDAL>().Keyed<IDAL>(DBType.Oracle); IContainer container = builder.Build(); SqlDAL sqlDAL = (SqlDAL)container.ResolveKeyed<IDAL>(DBType.Sql); OracleDAL oracleDAL = (OracleDAL)container.ResolveKeyed<IDAL>(DBType.Oracle);
6、IContainer.ResolveKeyed<IDAL>(Enum enum): //根据枚举值解析某个接口的特定实例。例如上面的最后一行代码就是解析IDAL的特定实例OracleDAL 7、builder.RegisterType<Worker>().InstancePerDependency()://用于控制对象的生命周期,每次加载实例时都是新建一个实例,默认就是这种方式 8、builder.RegisterType<Worker>().SingleInstance(): //用于控制对象的生命周期,每次加载实例时都是返回同一个实例 9、IContainer.Resolve<T>(NamedParameter namedParameter)://在解析实例T时给其赋值 DBManager manager = container.Resolve<DBManager>(new NamedParameter("name", "SQL")); public class DBManager { IDAL dal; public DBManager (string name,IDAL _dal) { Name = name; dal= _dal; }
} 10、通过配置的方式使用AutoFac (使用方式差不多,需要配置,比上面麻烦点,主要优势 例如实现数据库动态切换,避免程序重新编译,然并卵,谁没事换个数据库玩 先贴上) (1)修改App.config配置文件 一定要注意新建项目 会默认有这个 <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> //不能让他出现在<configuration> 下第一个节点,不然就报错, <?xml version="1.0"?> <configuration> <configSections> <section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/> </configSections> <autofac defaultAssembly="AutofacDemo"> <components> <component type="AutofacDemo.SqlDatabase, AutofacDemo" service="AutofacDemo.IDatabase" /> </components> </autofac> </configuration> 通过Autofac.Configuration.SectionHandler配置节点对组件进行处理。 (2)读取配置实现依赖注入(注意引入Autofac.Configuration.dll) static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<DBManager>(); builder.RegisterModule(new ConfigurationSettingsReader("autofac")); using (var container = builder.Build()) { var manager = container.Resolve<DBManager>(); manager.Add("INSERT INTO Persons VALUES ('Man', '25', 'WangW', 'Shanghai')"); } }
源码共享地址 : \\10.100.27.47\yebo750\Demo (打开我的电脑输入即可)