首页 > 代码库 > Autofac3 在MVC4中的运用原理

Autofac3 在MVC4中的运用原理

    这是一种新的开发模式,注入开发模式,或者叫它IOC模式,说起IOC你可以这样去理解它,它为你的某个实现流出一个注入点,你生产的对象,可以根据你之前的配置进行组合。  IOC全称是Inversion of Control,即反转控制,或者说是依赖注入更为合适。选择别纠结这些全称的专业词。我们可以用别外一些方式去理解它,IOC,是一种设计模式。它的延生所要实现的是把藕合从代码中移出去,统一放到XML文件中,通过一个容器在需要的时候把这个依赖关系形成,即把需要的接口实现注入到需要它的类中,这可能就是“依赖注入”说法的来源了。 

而注入点的位置及方式也是多种多样的,我们今天主要说一个通过HTTP请求进行注入的方式,IOC工具使用高效的Autofac,对它的认识你可以看这篇文章。


首先看一下我们这个项目的知识点:
MVC4一个对UI层进行分层的架构模式,在微软的MVC4中加入了开源的Razor引擎
EF(Entity Framework)这无疑是微软自己比较成功的ORM(Object Relational Mapping)工具(即对象关系映射,目前数据库是关系型数据库ORM 主要是把数据库中的关系数据映射称为程序中的对象),它执行效率上要高于linq to sql,甚至你自己编写的ado.net脚本。
Autofac这是在orchard项目中被广泛的IOC工具,它支持类型,反泛,HTTP等注入
对于这个系统的autofac部分,我们将它的注入点放在controller的构造函数中,将生产的对象配置在global中,当然,你也可以设置在config文件,或者你自己的文件中。
我认为它的工作方式应该是:
网站启动=>从global中得到ioc配置信息=>http request请求页面=>通过controller中的参数进行实现的创建=>action中使用创建好的对象

OK,有了这样一个理论基础,我们来看一下代码吧:

EF部分的DATA层

  1  public partial class EfRepository<T> : IRepository<T> where T : class  2     {  3         private readonly Guid _instanceId;  4         private readonly IDbContext _context;  5         private IDbSet<T> _entities;  6         public Guid InstanceId  7         {  8             get { return _instanceId; }  9         } 10         public EfRepository(IDbContext context) 11         { 12             AutoCommitEnabled = true; 13             this._context = context; 14             _instanceId = Guid.NewGuid(); 15         } 16         public T GetById(object id) 17         { 18             return this._entities.Find(id); 19         } 20         public T Create() 21         { 22             return this.Entities.Create(); 23         } 24         public void Insert(T entity) 25         { 26             try 27             { 28                 if (entity == null) 29                     throw new ArgumentNullException("entity"); 30                 this.Entities.Add(entity); 31                 if (this.AutoCommitEnabled) 32                     _context.SaveChanges(); 33             } 34             catch(DbEntityValidationException dbEx) 35             { 36                 var msg = string.Empty; 37                 foreach(var validationErrors in dbEx.EntityValidationErrors) 38                     foreach (var validationError in validationErrors.ValidationErrors) 39                         msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine; 40                 var fail = new Exception(msg, dbEx); 41                 throw fail; 42             } 43         } 44  45         public void InsertRange(IEnumerable<T> entities, int batchSize = 100) 46         { 47             try 48             { 49                 if (entities == null) 50                     throw new ArgumentNullException("entities"); 51                 if (entities.HasItems()) 52                 { 53                     if (batchSize <= 0) 54                     { 55                         entities.Each(x => this.Entities.Add(x)); 56                         if (this.AutoCommitEnabled) 57                             _context.SaveChanges(); 58                     } 59                     else 60                     { 61                         int i = 1; 62                         bool saved = false; 63                         foreach (var entity in entities) 64                         { 65                             this.Entities.Add(entity); 66                             saved = false; 67                             if (i % batchSize == 0) 68                             { 69                                 if (this.AutoCommitEnabled) 70                                     _context.SaveChanges(); 71                                 i = 0; 72                                 saved = true; 73                             } 74                             i++; 75                         } 76                         if (!saved) 77                         { 78                             if (this.AutoCommitEnabled) 79                                 _context.SaveChanges(); 80                         } 81                     } 82                 } 83             } 84             catch (DbEntityValidationException ex) 85             { 86                 throw ex; 87             } 88         } 89         public void Update(T entity) 90         { 91             if (entity == null) 92                 throw new ArgumentNullException("entity"); 93             try 94             { 95                 if (this.InternalContext.Entry(entity).State == EntityState.Detached) 96                 { 97                     var set = Entities; 98                     T attachedEntity = set.Find(entity.Key);  // You need to have access to key 99 100                     if (attachedEntity != null)101                     {102                         var attachedEntry = this.InternalContext.Entry(attachedEntity);103                         attachedEntry.CurrentValues.SetValues(entity);104                     }105                     else106                     {107                         // This should attach entity108                         this.InternalContext.Entry(entity).State = EntityState.Modified;109                     }110                 }111             }112             finally { }113 114             if (AutoCommitEnabled)115                 _context.SaveChanges();116         }117 118         public void Delete(T entity)119         {120             if (entity == null)121                 throw new ArgumentNullException("entity");122             if(InternalContext.Entry(entity).State==EntityState.Detached)123             {124                 this.Entities.Attach(entity);125             }126             this.Entities.Remove(entity);127             if (this.AutoCommitEnabled)128                 _context.SaveChanges();129         }130 131         public IDictionary<string, object> GetModifiedProperties(T entity)132         {133             var props = new Dictionary<string, object>();134 135             var ctx = InternalContext;136             var entry = ctx.Entry(entity);137             var modifiedPropertyNames = from p in entry.CurrentValues.PropertyNames138                                         where entry.Property(p).IsModified139                                         select p;140             foreach (var name in modifiedPropertyNames)141             {142                 props.Add(name, entry.Property(name).OriginalValue);143             }144 145             return props;146         }147         public virtual IQueryable<T> Table148         {149             get150             {151                 return this.Entities;152             }153         }154 155         public int Commit()156         {157             try158             {159                 return this._context.SaveChanges();160             }161             catch(DbEntityValidationException dbEx)162             {163                 var msg = string.Empty;164                 foreach (var validationErrors in dbEx.EntityValidationErrors)165                     foreach (var validationError in validationErrors.ValidationErrors)166                         msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);167 168                 var fail = new Exception(msg, dbEx);169                 throw fail;170             }171         }172         #region Helpers173         protected internal dwDbContextBase InternalContext174         {175             get { return _context as dwDbContextBase; }176         }177         public bool AutoCommitEnabled { get; set; }178 179         private DbSet<T> Entities180         {181             get182             {183                 if (_entities == null) { _entities = _context.Set<T>(); }184                 return _entities as DbSet<T>;185             }186         }187 188         #endregion189 190         public IQueryable<T> Include(IQueryable<T> query,string path)191         {192             Guard.ArgumentNotNull(query, "query");193             Guard.ArgumentNotEmpty(path, "path");194             return query.Include(path);195         }196         public IQueryable<T> Include<TProperty>(IQueryable<T> query,Expression<Func<T,TProperty>> path)197         {198             Guard.ArgumentNotNull(query, "query");199             Guard.ArgumentNotNull(path, "path");200             return query.Include(path);201         }202         public IDbContext Context203         {204             get { return _context; }205         }206 207     }

 Services层(BLL层)核心代码:

 1   public class TestService : BaseService, ITestService 2     { 3         private const string IncludeProperties = ""; 4         private readonly IRepository<Tests> _repository; 5         private readonly ICacheManager _cacheManager; 6         private readonly IExporter _exporter; 7         public IList<Tests> GetAll() 8         { 9             return _repository.FindBy(null, null, IncludeProperties).ToList();10         }11 12         public TestService(IRepository<Tests> repository,13             ICacheManager cacheManager,IExporter exporter,14             IEventPublisher eventPublisher):base(eventPublisher)15         {16             _repository = repository;17             _exporter = exporter;18             _cacheManager = cacheManager;19         }20 21     }

WEB层MVC部分代码:(注意:我们的WEB层不应该有对DATA层的引用,WEB层一般只注入SERVICE的对象,这一点是需要注意的,即不要直接调用数据库仓库)

 public class TestController : ApiController    {        private readonly ITestService _service;        private readonly Func<Tests, TestsModel, TestsModel> _convertCallback = (entity, model) => { return model; };        public TestController(ITestService service) { _service = service; }        public IEnumerable<TestsModel> Get()        {            var items = _service.GetAll();            var model = items.ConvertTo(_convertCallback);            return model;        }

而注入参数我们放在global中,看一下核心代码:

            //初始化依赖注入组件            var bootStrapper = new AutofacBootStrapper();            BootStrapperManager.Initialize(bootStrapper);            //设置依赖注入            GlobalConfiguration.Configuration.DependencyResolver = bootStrapper.GetWebApiDependencyResolver();            DependencyResolver.SetResolver(bootStrapper.GetMvcDependencyResolver());
 builder.Register(c => new dwObjectContext("MyConnection")).As<IDbContext>().InstancePerHttpRequest().InstancePerApiRequest();            builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>)).InstancePerHttpRequest().InstancePerApiRequest();            //注册缓存类型            builder.RegisterType<StaticCache>().As<ICache>().Named<ICache>(YB_CACHE_STATIC).SingleInstance();            builder.RegisterType<RequestCache>().As<ICache>().Named<ICache>(YB_CACHE_PER_REQUEST).InstancePerHttpRequest().InstancePerApiRequest();            //注册缓存控制类型            builder.RegisterType<NullCacheManager>()                .As<ICacheManager>()                .Named<ICacheManager>(YB_SM_CACHE_NULL)                .WithParameter(ResolvedParameter.ForNamed<ICache>(YB_CACHE_STATIC))                .SingleInstance();            builder.RegisterType<DefaultCacheManager>()                .As<ICacheManager>()                .Named<ICacheManager>(YB_SM_CACHE_PER_REQUEST)                .WithParameter(ResolvedParameter.ForNamed<ICache>(YB_CACHE_PER_REQUEST))                .InstancePerHttpRequest().InstancePerApiRequest();            builder.RegisterType<DefaultCacheManager>()               .As<ICacheManager>()                //.Named<ICacheManager>(YB_SM_CACHE_STATIC)               .WithParameter(ResolvedParameter.ForNamed<ICache>(YB_CACHE_STATIC))               .SingleInstance();            var assembly = Assembly.GetExecutingAssembly();            //注册所有 MVC 控制器            builder.RegisterControllers(assembly)                .InstancePerHttpRequest();            //注册所有 Web Api 控制器            builder.RegisterApiControllers(assembly)                .InstancePerApiRequest();

 

Autofac3 在MVC4中的运用原理