AutoFac (控制反转IOC 与依赖注入DI)
重要的参考资料http://www.cnblogs.com/xdp-gacl/p/4249939.html
谈谈对Spring IOC的理解
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace FB.CMS.MvcSite.App_Start
{
using Autofac;
using Autofac.Integration.Mvc;
using System.Reflection;
using System.Web.Mvc; /// <summary>
/// 这个类是我自己定义的一个类,主要用初始化AutoFac容器的相关数据
/// </summary>
public class AutoFacConfig
{ public static void Register()
{
//初始化AutoFac的相关功能
/*
1.0 告诉AutoFac初始化数据仓储层FB.CMS.Repository.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
2.0 告诉AutoFac初始化业务逻辑层FB.CMS.Services.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
3.0 将MVC默认的控制器工厂替换成AutoFac的工厂
*/ //第一步: 构造一个AutoFac的builder容器
ContainerBuilder builder = new Autofac.ContainerBuilder(); //第二步:告诉AutoFac控制器工厂,控制器类的创建去哪些程序集中查找(默认控制器工厂是去扫描bin目录下的所有程序集)
//2.1 从当前运行的bin目录下加载FB.CMS.MvcSite.dll程序集
Assembly controllerAss = Assembly.Load("FB.CMS.MvcSite"); //2.2 告诉AutoFac控制器工厂,控制器的创建从controllerAss中查找(注意:RegisterControllers()方法是一个可变参数,如果你的控制器类的创建需要去多个程序集中查找的话,那么我们就再用Assembly controllerBss=Assembly.Load("需要的程序集名")加载需要的程序集,然后与controllerAss组成数组,然后将这个数组传递到RegisterControllers()方法中)
builder.RegisterControllers(controllerAss); //第三步:告诉AutoFac容器,创建项目中的指定类的对象实例,以接口的形式存储(其实就是创建数据仓储层与业务逻辑层这两个程序集中所有类的对象实例,然后以其接口的形式保存到AutoFac容器内存中,当然如果有需要也可以创建其他程序集的所有类的对象实例,这个只需要我们指定就可以了) //3.1 加载数据仓储层FB.CMS.Repository这个程序集。
Assembly repositoryAss = Assembly.Load("FB.CMS.Repository");
//3.2 反射扫描这个FB.CMS.Repository.dll程序集中所有的类,得到这个程序集中所有类的集合。
Type[] rtypes = repositoryAss.GetTypes();
//3.3 告诉AutoFac容器,创建rtypes这个集合中所有类的对象实例
builder.RegisterTypes(rtypes)
.AsImplementedInterfaces(); //指明创建的rtypes这个集合中所有类的对象实例,以其接口的形式保存 //3.4 加载业务逻辑层FB.CMS.Services这个程序集。
Assembly servicesAss = Assembly.Load("FB.CMS.Services");
//3.5 反射扫描这个FB.CMS.Services.dll程序集中所有的类,得到这个程序集中所有类的集合。
Type[] stypes = servicesAss.GetTypes();
//3.6 告诉AutoFac容器,创建stypes这个集合中所有类的对象实例
builder.RegisterTypes(stypes)
.AsImplementedInterfaces(); //指明创建的stypes这个集合中所有类的对象实例,以其接口的形式保存 //第四步:创建一个真正的AutoFac的工作容器
var container = builder.Build(); //我们已经创建了指定程序集的所有类的对象实例,并以其接口的形式保存在AutoFac容器内存中了。那么我们怎么去拿它呢?
//从AutoFac容器内部根据指定的接口获取其实现类的对象实例
//假设我要拿到IsysFunctionServices这个接口的实现类的对象实例,怎么拿呢?
//var obj = container.Resolve<IsysFunctionServices>(); //只有有特殊需求的时候可以通过这样的形式来拿。一般情况下没有必要这样来拿,因为AutoFac会自动工作(即:会自动去类的带参数的构造函数中找与容器中key一致的参数类型,并将对象注入到类中,其实就是将对象赋值给构造函数的参数) //第五步:将当前容器中的控制器工厂替换掉MVC默认的控制器工厂。(即:不要MVC默认的控制器工厂了,用AutoFac容器中的控制器工厂替代)此处使用的是将AutoFac工作容器交给MVC底层 (需要using System.Web.Mvc;)
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); //我们知道控制器的创建是调用MVC默认的控制器工厂,默认的控制器工厂是调用控制器类的无参构造函数
//可是我们如果要使用AutoFac自动工厂,将对象通过构造函数注入类中,那么这个构造函数就需要带参数
//如果我们将控制器的无参构造函数删除,保留带参数的构造函数,MVC默认的控制器工厂来创建控制的时候
//就会去调用无参的构造函数,可是这时候发现没有无参的构造函数于是就报“没有为该对象定义无参数的构造函数”错误
//既然报错,那我们如果保留无参的构造函数,同时在声明一个带参数的构造函数是否可行呢?
//答案;行是行,但是创建控制器的时候,MVC默认的控制器工厂调用的是无参构造函数,它并不会去调用有参的构造函数
//这时候,我们就只能将AutoFac它的控制器工厂替换调用MVC默认的控制器工厂(控制器由AutoFac的控制器工厂来创建)
//而AutoFac控制器工厂在创建控制的时候只会扫描带参数的构造函数,并将对象注入到带参数的构造函数中
//AutofacDependencyResolver这个控制器工厂是继承了 IDependencyResolver接口的,而IDependencyResolver接口是MVC的东西
//MVC默认的控制器工厂名字叫:DefaultControllerFactory
//具体参考:http://www.cnblogs.com/artech/archive/2012/04/01/controller-activation-032.html }
}
}
然后我们在Global.asax文件中的Application_Start()方法中来调用这个类
using FB.CMS.MvcSite.App_Start;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing; namespace FB.CMS.MvcSite
{
// 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
// 请访问 http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{ AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); //第一: 在网站一启动的时候就初始化AutoFac的相关功能
/*
1.0 告诉AutoFac初始化数据仓储层FB.CMS.Repository.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
2.0 告诉AutoFac初始化业务逻辑层FB.CMS.Services.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
3.0 将MVC默认的控制器工厂替换成AutoFac的工厂
*/ //具体做法就是我们去App_Start文件夹下创建一个AutoFacConfig类,具体实现什么功能去这个类中实现。然后再这里调用下这个类
AutoFacConfig.Register();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace FB.CMS.MvcSite.Controllers
{
using FB.CMS.IServices;
public class HomeController : Controller
{
IsysFunctionServices dal;
public HomeController(IsysFunctionServices dal) //依赖构造函数进行对象注入
{
this.dal = dal; //在构造函数中初始化HomeController控制器类的dal属性 (这个dal属性的类型是IsysFunctionServices)
} public ActionResult Index()
{
var a = dal.QueryWhere(r => r.fID > ).ToList(); //查询
return View();
}
}
}
用AutoFac 在一个控制器下通过构造函数,注入多个对象的时候,我们可以对BaseDal进行优化
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace FB.CMS.Repository
{
using FB.CMS.IRepository;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using System.Threading;
public class BaseDal<TEntity> : IBaseDal<TEntity> where TEntity : class
{
//BaseDbContext db = new BaseDbContext(); //对创建上下文容器类对象进行优化(原理:一个线程下我们只创建一个上下文容器类对象,然后保存到线程缓存当中去,当同一个线程过来的时候,就从线程缓存当中取上下文容器类对象)
public BaseDbContext db
{
get
{
//获取BaseDbContext的完全限定名,其实这个名字没什么特别的意义,仅仅是一个名字而已,也可以取别的名字的
string threadName = typeof(BaseDbContext).FullName;
//获取key为threadName的这个线程缓存(CallContext就是线程缓存容器类)
object dbObj = CallContext.GetData(threadName);
//如果key为threadName的线程缓存不存在
if (dbObj == null)
{
//创建BaseDbContext类的对象实例
dbObj = new BaseDbContext();
//将这个BaseDbContext类的对象实例保存到线程缓存当中(以键值对的形式进行保存的,我这就将key设为当前线程的完全限定名了)
CallContext.SetData(threadName, dbObj);
return dbObj as BaseDbContext;
}
return dbObj as BaseDbContext;
} }
DbSet<TEntity> _dbset;
public BaseDal()
{
this._dbset = db.Set<TEntity>(); //初始化
} #region 增加
public void AddEnity(TEntity model)
{
if (model == null)
{
throw new Exception("moddel不能为null");
}
this._dbset.Add(model); } #endregion #region 物理删除
/// <summary>
/// 删除
/// </summary>
/// <param name="model">实体类</param>
/// <param name="isaddedContext">是否物理删除</param>
public void DeleteEntity(TEntity model, bool isaddedContext)
{
if (model == null)
{
throw new Exception("DeleteEntity方法中的model不能为null");
}
//如果仅仅是逻辑删除的话,那我们只要调用编辑方法将标识为逻辑删除的那个字段修改为true就可以了。
if (isaddedContext == true)
{
this._dbset.Attach(model); }
this._dbset.Remove(model);
} #endregion #region 查寻
/// <summary>
/// 普通带条件查询
/// </summary>
/// <param name="where"></param>
/// <returns></returns>
public IQueryable<TEntity> QueryWhere(Expression<Func<TEntity, bool>> where)
{
return this._dbset.Where(where);
} /// <summary>
/// 连表查询
/// </summary>
/// <param name="where">连表查询的条件筛选查询</param>
/// <param name="tablesName">要做连表查询的所有表名集合</param>
/// <returns></returns>
public IQueryable<TEntity> QueryJoin(Expression<Func<TEntity, bool>> where, string[] tablesName)
{
if (tablesName == null || tablesName.Any() == false)
{
throw new Exception("连表查询最少也要一个表,所有QueryJoin方法中tablesName中最少也需要有一个表名");
} DbQuery<TEntity> query = this._dbset;
foreach (string tableName in tablesName)
{
//不断的连表,直到把tablesName里的所有表都连完
query = query.Include(tableName);
}
return query.Where(where); //然后对连表进行条件筛选查询
} /// <summary>
/// 带条件的分页查询
/// </summary>
/// <typeparam name="TKey">按哪个字段进行排序</typeparam>
/// <param name="pageindex">当前页</param>
/// <param name="pagesize">页大小</param>
/// <param name="rowCount">数据总条数</param>
/// <param name="order">排序</param>
/// <param name="where">筛选条件</param>
/// <returns></returns>
public IQueryable<TEntity> QueryByPage<TKey>(int pageindex, int pagesize, out int rowCount, Expression<Func<TEntity, TKey>> order, Expression<Func<TEntity, bool>> where)
{
//获取总条数
rowCount = this._dbset.Count(where); //建议将这个Where条件语句放在前面,如果你放到后面,分页的时候可能存在问题。
return this._dbset.Where(where).OrderByDescending(order).Skip((pageindex - ) * pagesize).Take(pagesize); } /// <summary>
/// 调用存储过程或执行SQL语句(但是我们不推荐执行sql语句)
/// </summary>
/// <typeparam name="TElement">
/// 因为存储过程返回的数据不一定就是TEntity这个实体,因为存储过返回的结果集有可能是自己拼接出来的,所以这个方法的返回结果
/// 为Lsit<TEntity>就不合适了。 这个 TElement是在调用的存储过程的时候传入的一个实体,此实体必须和调用的存储过程的返回结集
/// 中的字段名称保存一致(你这个存储过程返回有多个字段,那么你这个实体中就应该有多少个属性)
/// </typeparam>
/// <param name="sql">
/// 假设我创建了这么一个存储过程:
/// create proc proc_T_UserInfo_Paging2(@pageSize int,@currentPage int,@CountData )
/// 那现在我们调用这个存储过程,那么这个SQL语句的写法就是:
/// proc_T_UserInfo_Paging2 @pageSize int,@currentPage int,@CountData ///
/// </param>
/// <param name="prms">参数化查询的参数数组</param>
/// <returns></returns>
public List<TElement> RunProc<TElement>(string sql, params object[] prms)
{
return db.Database.SqlQuery<TElement>(sql, prms).ToList();
}
#endregion #region 编辑
/// <summary>
/// 编辑
/// </summary>
/// <param name="model">实体</param>
/// <param name="propertyNames">要编辑的的所有属性名称序列</param>
public void EditEntity(TEntity model, string[] propertyNames)
{
if (model == null)
{
throw new Exception("EditEntity方法中的参数model不能为null");
}
if (propertyNames.Any() == false || propertyNames == null)
{
throw new Exception("EditEntity方法中的参数propertyNames最少需要一个属性");
}
System.Data.Entity.Infrastructure.DbEntityEntry entry = db.Entry(model);
entry.State = System.Data.EntityState.Unchanged;
foreach (string item in propertyNames)
{
entry.Property(item).IsModified = true;
}
db.Configuration.ValidateOnSaveEnabled = false;
} #endregion #region 统一保存
public int SaveChanges()
{
return db.SaveChanges();
}
#endregion
}
}
Home控制器
直接在控制器中使用方式是
public ActionResult Index()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<UserInfoSevices>(); //想拿到UserInfoSevices类的实例
builder.RegisterType<UserInfoRepository>().As<IUserInfoRepository>(); //与之关联的UserInfoRepository类也需要拿到,并转化成接口的形式保存
var aa = builder.Build().Resolve<UserInfoSevices>().QueryModel(r => r.Age > ); //在这里使用 return View();
}
AutoFac (控制反转IOC 与依赖注入DI)的更多相关文章
- 控制反转IOC与依赖注入DI
理解 IOC http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例 的http:// ...
- 控制反转(Ioc)和依赖注入(DI)
控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...
- iOS控制反转(IoC)与依赖注入(DI)的实现
背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大 ...
- 轻松学,浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI) 依赖注入和控制反转的理解,写的太好了。
轻松学,浅析依赖倒置(DIP).控制反转(IOC)和依赖注入(DI) 2017年07月13日 22:04:39 frank909 阅读数:14269更多 所属专栏: Java 反射基础知识与实战 ...
- 控制反转IOC与依赖注入DI【转】
转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...
- 【转载】浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
原文地址 http://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...
- 控制反转IOC与依赖注入DI - 理论篇
学无止境,精益求精 十年河东十年河西,莫欺少年穷 昨天是五一小长假归来上班的第一天,身体疲劳,毫无工作热情.于是就看看新闻,喝喝茶,荒废了一天 也就在昨天,康美同事张晶童鞋让我学习下IOC的理论及实现 ...
- 依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
原文: https://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...
- 20181123_控制反转(IOC)和依赖注入(DI)
一. 控制反转和依赖注入: 控制反转的前提, 是依赖倒置原则, 系统架构时,高层模块不应该依赖于低层模块,二者通过抽象来依赖 (依赖抽象,而不是细节) 如果要想做到控制反转(IOC), 就必须要使 ...
随机推荐
- 大前端学习笔记【七】关于CSS再次整理
如果你在日常工作中使用 CSS,你的主要目标可能会重点围绕着使事情“看起来正确”.如何实现这一点经常是远不如最终结果那么重要.这意味着比起正确的语法和视觉结果来说,我们更少关心 CSS 的工作原理. ...
- win10传奇手册CHM打开无法阅读解决
今天在阅读传奇的帮助文档时候,突然遇到了一个问题.打开为空白. 如图所示 我这个情况打开的时候会提示 这个时候我们把 打开此文件总是询问 这个对勾 去掉 惊喜有没有. 哈哈 .有问题欢迎大家私信我!
- python 方法
1.首先运行python交互模式 输入 python 2.定义一个有序的集合 相当于js中的数组它里面有一些增删改查的方法 1. 定义一个数组 >>> ww = ['1','2',' ...
- <笔记>更新某条数据库记录必须更新所有字段
今天用TP更新数据库数据时,用id得到模型对象,再通过该对象更新其他字段的数据,发现报错
- Hadoop2.0源码包简介
Hadoop2.0源码包简介 1.解压源码包: 2.目录结构: hadoop-common-project:Hadoop基础库所在目录,如RPC.Metrics.Counter等.包含了其它所有模块可 ...
- java持有对象-集合类
面阿里的时候,面试就让我说一下集合 当时由于条件原因没听清面试官的问题,后来面试后,面试官让问他问题的时候,才说明白是什么 下面就接受一下我了解的集合类 集合类中大致可以分为两个体系 一.collec ...
- iOS 数组问题
在iOS开发过程中,使用json抓取网络数据进行解析时,用tableview承载,发现数据已经抓取到,但是在cell里面使用却会导致程序崩溃 原因可能是初始化方法问题,将 _infoArray=[[N ...
- Fiddler工具使用介绍一
Fiddler基础知识 Fiddler是强大的抓包工具,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888,我们也可以通过设置进行修改. 代理就是在 ...
- 一篇入门 -- Scala 反射
本篇文章主要让大家理解什么是Scala的反射, 以及反射的分类, 反射的一些术语概念和一些简单的反射例子. 什么是反射 我们知道, Scala是基于JVM的语言, Scala编译器会将Scala代码编 ...
- Windows下编译安装 FFmpeg
在Linux/Mac下编译 ffmpeg是非常方便的.但要在 Windows下编译 ffmpeg还真要花点时间.以下就是在 Windowns下编译ffmpeg的步骤: 一.安装Cygwin 在wind ...