一步一步学EF系列【6、IOC 之AutoFac】

前言

之前的前5篇作为EF方面的基础篇,后面我们将使用MVC+EF 并且使用IOC ,Repository,UnitOfWork,DbContext来整体来学习。因为后面要用到IOC,所以本篇先单独先学习一下IOC,我们本本文单独主要学习Autofac,其实对于Autofac我也是边学边记录。不对的地方,也希望大家多多指导。

个人在学习过程中参考博客:

AutoFac文档:http://www.cnblogs.com/wolegequ/archive/2012/06/09/2543487.html

AutoFac使用方法总结:Part I:http://niuyi.github.io/blog/2012/04/06/autofac-by-unit-test/

为什么使用AutoFac?

Autofac是.NET领域最为流行的IOC框架之一,传说是速度最快的一个:

优点:

  • 它是C#语言联系很紧密,也就是说C#里的很多编程方式都可以为Autofac使用,例如可以用Lambda表达式注册组件

  • 较低的学习曲线,学习它非常的简单,只要你理解了IoC和DI的概念以及在何时需要使用它们
  • XML配置支持
  • 自动装配
  • 与Asp.Net MVC 集成
  • 微软的Orchad开源程序使用的就是Autofac,从该源码可以看出它的方便和强大

上面的优点我也是拷的别人文章里面的,上面的这个几乎所有讲Autofac博文都会出现的。这个也是首次学习,所以我们还是记录的细一点。

怎么使用Autofac

通过VS中的NuGet来加载AutoFac,引入成功后引用就会出现Autofac。

1、我们做一个简单的例子先用一下

就拿数据访问来做案例把,一个数据请求有两个类,一个是Oracle 一个是SQLSERVER。我们在使用的时候可以选择调用那个数据库。

1.1 我们先定义一个数据访问的接口和访问类。

/// <summary>
    /// 数据源操作接口
    /// </summary>
    public interface IDataSource
    {
        /// <summary>
        /// 获取数据
        /// </summary>
        /// <returns></returns>
        string GetData();
    }
/// <summary>
    /// SQLSERVER数据库
    /// </summary>
    class Sqlserver : IDataSource
    {
        public string GetData()
        {
            return "通过SQLSERVER获取数据";
        }
    }
/// <summary>
    /// ORACLE数据库
    /// </summary>
    public class Oracle : IDataSource
    {
        public string GetData()
        {
            return "通过Oracle获取数据";
        }
    }

最普通的方式大家都会的吧! 如果最普通的方式调用SQLSERVER怎么写?

static void Main(string[] args)
        {
            IDataSource ds = new Sqlserver();

            Console.WriteLine(ds.GetData());

            Console.ReadLine();
        }
调用Oracle的话new Oracle()就可以了。如果这个都不能理解的话,那学习这个你就很费劲了。

改进一下代码。我们在加入一个DataSourceManager类来看一下

/// <summary> 
/// 数据源管理类
/// </summary
public class DataSourceManager
    {

        IDataSource _ds;
        /// <summary>
        /// 根据传入的类型动态创建对象
        /// </summary>
        /// <param name="ds"></param>
        public DataSourceManager(IDataSource ds)
        {
            _ds = ds;
        }

        public string GetData()
        {
            return _ds.GetData();
        }
    }

这样写的好处是什么,这样加入加入新的数据源,只用调用的时候传入这个对象就可以,就会自动创建一个对应的对象。那接下如果要调用SQLSERVER怎么写。看代码

DataSourceManager dsm = new DataSourceManager(new Sqlserver());
Console.WriteLine(dsm.GetData());

Console.ReadLine();

1.2 注入实现构造函数注入

上面的DataSourceManager的动态创建的方式就是因为又有个带IDataSource的参数的构造函数,只要调用者传入实现该接口的对象,就实现了对象创建。

那我们看看怎么使用AutoFac注入实现构造函数注入

var builder = new ContainerBuilder();
            builder.RegisterType<DataSourceManager>();
            builder.RegisterType<Sqlserver>().As<IDataSource>();

            using (var container = builder.Build())
            {
                var manager = container.Resolve<DataSourceManager>();
                Console.WriteLine(manager.GetData());

                Console.ReadLine();
            }

上面的就是AutoFac构造函数注入,他给IDataSource注入的是Sqlserver所以我们调用的数据,返回的就是Sqlserver数据。那下面我们具体的了解一下AutoFac的一些方法

1.3 Autofac方法说明

(1)builder.RegisterType<Object>().As<Iobject>():注册类型及其实例。例如上面就是注册接口IDataSource的实例Sqlserver
(2)IContainer.Resolve<IDAL>():解析某个接口的实例。例如一下代码,我可以解析接口返回的就是Sqlserver实例

var builder = new ContainerBuilder();
         //builder.RegisterType<DataSourceManager>();
         builder.RegisterType<Sqlserver>().As<IDataSource>();

using (var container = builder.Build())
         {
             var manager = container.Resolve<IDataSource>();
             Console.WriteLine(manager.GetData());

Console.ReadLine();
     }

(3)builder.RegisterType<Object>().Named<Iobject>(string name):为一个接口注册不同的实例。有时候难免会碰到多个类映射同一个接口,比如Sqlerver和Oracle都实现了IDalSource接口,为了准确获取想要的类型,就必须在注册时起名字。
var builder = new ContainerBuilder();
            builder.RegisterType<Sqlserver>().Named<IDataSource>("SqlServer");
            builder.RegisterType<Oracle>().Named<IDataSource>("Oracel");
            using (var container = builder.Build())
            {
                var manager = container.ResolveNamed<IDataSource>("Oracel");
                Console.WriteLine(manager.GetData());
                Console.ReadLine();
            }

运行后的代码。

(4)IContainer.ResolveNamed<IDAL>(string name):解析某个接口的“命名实例”。例如上面的实例最后一行代码container.ResolveNamed<IDataSource>("Oracel"); 就是解析IDataSource的命名实例Oracel。
(5)builder.RegisterType<Object>().Keyed<Iobject>(Enum enum):以枚举的方式为一个接口注册不同的实例。有时候我们会将某一个接口的不同实现用枚举来区分,而不是字符串。
    这个方法是完全可以替代builder.RegisterType<Object>().Named<Iobject>(string name),这个列子就不演示了吧!和上面的一个意思。
 
(6)IContainer.ResolveKeyed<IDAL>(Enum enum):根据枚举值解析某个接口的特定实例。这个和上面的都一样 也就不演示了。
(7)builder.RegisterType<Worker>().InstancePerDependency():用于控制对象的生命周期,每次加载实例时都是新建一个实例,默认就是这种方式。调用的话
builder.RegisterType<Sqlserver>().Keyed<IDataSource>("Sqlserver").InstancePerDependency();
(8)builder.RegisterType<Worker>().SingleInstance():用于控制对象的生命周期,每次加载实例时都是返回同一个实例
(9)IContainer.Resolve<T>(NamedParameter namedParameter):在解析实例T时给其赋值,这个就是给你定义的方法的参数传值。
        IDataSource _ds;
        string Name;
        /// <summary>
        /// 根据传入的类型动态创建对象
        /// </summary>
        /// <param name="ds"></param>
        public DataSourceManager(string name, IDataSource ds)
        {
            _ds = ds;
            Name = name;
        }

        public string GetData()
        {
            return Name + ":" + _ds.GetData();
        }

我把DataSourceManager的构造方法加了个name参数,然后我调用的时候:

var manager = container.Resolve<DataSourceManager>(new NamedParameter("name", "STONE刘先生"));

运行后的代码:

1.4 通过配置的方式使用AutoFac

在演示一下怎么通过配置文件来配置注册。这块就简单讲,下面的是我的web.config。

<configuration>
  <configSections>
    <section name="autofac" type="Autofac.Configuration.SectionHandler,Autofac.Configuration"></section>
  </configSections>
  <autofac defaultAssembly="AutoFacDemo">
    <components>
      <component  type="AutoFacDemo.Model.Oracle,AutoFacDemo" service="AutoFacDemo.Model.IDataSource" />
    </components>
  </autofac>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>

后台的调用代码

var builder = new ContainerBuilder();
            builder.RegisterType<DataSourceManager>();
            builder.RegisterModule(new ConfigurationSettingsReader("autofac"));

            using (var container = builder.Build())
            {
                var manager = container.Resolve<DataSourceManager>(new NamedParameter("name", "STONE刘先生"));
                Console.WriteLine(manager.GetData());

                Console.ReadLine();
            }

这里需要注意的是需要引用Autofac.Configuration.dll,否则没有办法使用ConfigurationSettingsReader。

还有一个需要注意的就是你的配置文件要命名空间,类名要写对。

动手尝试一下吧!

MVC下面使用Autofac

引用和上面的控制台程序的原理是一模一样的。但是区别就在于要多添加一个引用

案例还是用上面的案例。我是把之前的接口和类拷贝到MVC项目里面作为下面演示。代码就不在写出来了,一模一样的。

1、首先在函数Application_Start() 注册自己的控制器类

MVC下怎么配置可以直接看如下代码,我把注释写的也很详细。

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            //创建autofac管理注册类的容器实例
            var builder = new ContainerBuilder();
            //下面就需要为这个容器注册它可以管理的类型
            //builder的Register方法可以通过多种方式注册类型,之前在控制台程序里面也演示了好几种方式了。
            builder.RegisterType<Sqlserver>().As<IDataSource>();

            //builder.RegisterType<DefaultController>().InstancePerDependency();
            //使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册
            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            //生成具体的实例
            var container = builder.Build();
            //下面就是使用MVC的扩展 更改了MVC中的注入方式.
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

        }

需要解释的是:

1、大家看下面的这句,这句的作用就是再MVC下面你必须要注册一下Controller,否则没有办法注入。

//使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册
            builder.RegisterControllers(Assembly.GetExecutingAssembly());

我们通过使用RegisterControllers就可以解决。那如果不用RegisterControllers 我就想一个个注册的话怎么弄?学技术有时候不要只管会用有的时候你也要理解人家提供的方法背后是怎么做的。看到这里你知道怎么做么?先考虑1分钟,不要记得往下看。答案其实在上面讲控制台程序使用Autofac的时候已经讲过了。好吧,我来详细讲一下,我先把之前控制台程序的代码贴出来。

public class DataSourceManager
    {
        IDataSource _ds;
        string Name;
        /// <summary>
        /// 根据传入的类型动态创建对象
        /// </summary>
        /// <param name="ds"></param>
        public DataSourceManager(string name, IDataSource ds)
        {
            _ds = ds;
            Name = name;
        }
        public string GetData()
        {
            return Name + ":" + _ds.GetData();
        }
    }
这个类还记得吗?不记得在看之前写的文章。这个类有个IDataSource 作为参数的构造方法。然后我们在看一下使用时候的代码?
            var builder = new ContainerBuilder();
            builder.RegisterType<DataSourceManager>();
            builder.RegisterType<Sqlserver>().As<IDataSource>();

            using (var container = builder.Build())
            {
                var manager = container.Resolve<DataSourceManager>(new NamedParameter("name", "STONE刘先生"));
                Console.WriteLine(manager.GetData());

                Console.ReadLine();
            }

看到了吗?container.Resolve<DataSourceManager>()这里通过Resolve解析DataSourceManager实例,对于DataSourceManager类型,我们为Autofac提供了类型, 但是当Autofac创建DataSourceManager的实例, 调用它的构造函数的时候,它的构造函数需要提供一个IDataSource的实例作为参数的,Autofac会在自己的容器里,找注册过IDataSource的实例,并且通过AsImplementedInterfaces()方法,指明为接口IDataSource提供的实例。然后作为创建DataSourceManager时,提供给构造函数的参数。这整个原理不知道这样讲你能听懂吗?

大家上面提出的如果不用RegisterControllers来,需要手动添加怎么做?答案就是要写若干个这个方法。

builder.RegisterType<DefaultController>().InstancePerDependency();
注:DefaultController 控制器的名称,你可要试着把RegisterControllers删除掉,用上面的这句来尝试一下。但是实际的项目中最好是用RegisterControllers。

2、如果没有写builder.RegisterControllers<> ,而且控制器也没有通过builder.RegisterType<>注册, 你会看到如下的错误

整个MVC 使用autofac配置的工作就完成了。那接下来直接来看代码里面怎么使用。

2、   添加控制器,并注入依赖代码

public class DefaultController : Controller
    {

        IDataSource ds;
        // 接口定义  构造函数注入
        public DefaultController(IDataSource _ds)
        {
            ds = _ds;
        }

        // GET: Default
        public ActionResult Index()
        {
            //调用具体类的具体方法返回结果 赋值给ViewBag.Message
            ViewBag.Message = "STONE刘先生:" + ds.GetData();
            return View();
        }
    }

整个功能请求的数据添加到ViewBag然后在页面上面显示出来,也比较简单的。

运行后的效果:

成功了!

结语

终于把AutoFac这篇完成了,有不对的地方,还以为各位能多多指点,共同学习进步。初次写系列文章,真的有点佩服在博客园分享的各位大牛了,这个真的是很耗费时间和精力的,以后更应该尊重别人的知识分享。

大家也可以加入QQ群进行交流(435498053)。

作者:STONE刘先生 出处:http://www.cnblogs.com/liupeng/

本文版权归作者和博客园共有,欢迎转载。未经作者同意下,必须在文章页面明显标出原文链接及作者,否则保留追究法律责任的权利。
如果您认为这篇文章还不错或者有所收获,可以点击右下角的【推荐】按钮,因为你的支持是我继续写作,分享的最大动力!

时间: 2024-10-22 03:11:57

一步一步学EF系列【6、IOC 之AutoFac】的相关文章

一步一步学EF系列【4、升级篇 实体与数据库的映射】live writer真坑,第4次补发

前言 之前的几篇文章,被推荐到首页后,又被博客园下了,原因内容太少,那我要写多点呢,还是就按照这种频率进行写呢?本身我的意图这个系列就是想已最简单最容易理解的方式进行,每篇内容也不要太多,这样初学者容易理解学习,否则天花乱坠的一大篇初学者从头看到尾也要晕了.所以每次突出重点进行浓缩精华时的讲,当然我这样精简讲,你们要学深入的话,也还是要把有些概念学深入一下.也欢迎大家共同讨论学习.我这里创建了一个QQ群(435498053),大家也可以加群交流. 正文 本篇还是作为之前的升级篇,其实前面2-3篇

一步一步学EF系列【5、升级篇 实体与数据库的映射】live writer真坑,第4次补发

前言 之前的几篇文章,被推荐到首页后,又被博客园下了,原因内容太少,那我要写多点呢,还是就按照这种频率进行写呢?本身我的意图这个系列就是想已最简单最容易理解的方式进行,每篇内容也不要太多,这样初学者容易理解学习,否则天花乱坠的一大篇初学者从头看到尾也要晕了.所以每次突出重点进行浓缩精华时的讲,当然我这样精简讲,你们要学深入的话,也还是要把有些概念学深入一下.也欢迎大家共同讨论学习.我这里创建了一个QQ群(435498053),大家也可以加群交流. 正文 本篇还是作为之前的升级篇,其实前面2-3篇

一步一步学EF系列【3、数据迁移】

我们每篇的内容都不多,所以希望在学习的过程中最后能亲自敲一下代码 这样更有利于掌握. 我们现在接着上篇的例子,我们现在给随便的表增加一个字段 CreateTime 创建日期 运行一下 看看会怎么样 修改实体类,代码给大家分享一下 public partial class Post { /// <summary> /// 随笔的主键id /// </summary> public int PostId { get; set; } // 随笔的标题 public string Post

一步一步学EF系列【2、Fluent API的方式来处理实体与数据表之间的映射关系。】

EF里面的默认配置有两个方法,一个是用Data Annotations(在命名空间System.ComponentModel.DataAnnotations;),直接作用于类的属性上面,还有一个就是Fluent API,通过新增相应的配置类来覆盖默认配置另外.我们主要学习Fluent API,Data Annotations可以自行去学习一下. 补充一下为什么要用Fluent API 使用DataAnnotation非常简单,但对于EntityFramework中的特性,就要在实体类中引入Ent

Linux C编程学习5---参考《那年,一步一步学linux c》全系列(目录索引)

漫无目的的搜索一些东西,发现的一个很好的资源,所以就一定要收藏下来,方便自己学习Linux C 的时候也能够去参考一下别人的学习之路,来更加促进我的学习和思考 说明 转载请注明出处:谢谢:http://blog.csdn.net/muge0913/article/details/7342977 博主的邮箱是:[email protected] 文章中若有不对或某些功能更好的实现方法,请指出或直接留言. 该系列文章中所用结构数据代码均来自linux2.6.39. 1.那年,一步一步学linux c

一步一步学Linq to sql系列文章 转lovecherry

http://www.cnblogs.com/lovecherry/archive/2007/08/13/853754.html 现在Linq to sql的资料还不是很多,本人水平有限,如果有错或者误导请指出,谢谢. 一步一步学Linq to sql(一):预备知识 一步一步学Linq to sql(二):DataContext与实体 一步一步学Linq to sql(三):增删改 一步一步学Linq to sql(四):查询句法 一步一步学Linq to sql(五):存储过程 一步一步学L

Rhythmk 一步一步学 JAVA (21) JAVA 多线程

1.JAVA多线程简单示例 1.1 .Thread  集成接口 Runnable 1.2 .线程状态,可以通过  Thread.getState()获取线程状态: New (新创建) Runnable (可以运行) Blocked  (被阻塞) Waiting  (等待) Timed waiting (计时等待) Terminated  (被终止) ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

Rhythmk 一步一步学 JAVA (22) JAVA 网络编程

1.获取主机信息 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test     public void GetDomainInfo() throws UnknownHostException {         String domain = "www.baidu.com";         InetAddress netAddress = InetAddress.getByName(domain);         // 获取

一步一步学ROP之linux_x64篇

一步一步学ROP之linux_x64篇 一.序 **ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防御(比如内存不可执行和代码签名等).上次我们主要讨论了linux_x86的ROP攻击:<一步一步学ROP之linux_x86篇>,在这次的教程中我们会带来上一篇的补充以及linux_x64方面的ROP利用方法,欢迎大家继续学习. 另外文中涉及代码可在我的github下载:https://githu