IOC之Unity的使用详解

原文链接:https://www.cnblogs.com/hua66/p/9670639.html

 Unity作为Microsoft推出IOC容器,其功能是非常丰富的,其中需要注意的地方也不少。以下是个人在项目中使用Unity的场景并附实例。

一、封装数据访问层

  1、定义对象与DB交互接口  

 1 public interface IBaseService : IDisposable
 2     {
 3         T FindEntity<T>(int id) where T : class;
 4         void AddEntity<T>(T entity) where T : class;
 5         Task<int> AddEntities<T>(IEnumerable<T> entities) where T : class;
 6         void UpdateEntity<T>(T entity) where T : class;        
 7         Task<int> UpdateEntities<T>(IEnumerable<T> entities) where T : class;
 8         void DeleteEntity<T>(int id) where T : class;
 9         void DeleteEntity<T>(T entity) where T : class;
10         Task<int> DeleteEntities<T>(IEnumerable<T> entities) where T : class;
11         Task<int> DeleteEntities<T>(Func<T, bool> whereLambda) where T : class;
12         IQueryable<T> LoadEntities<T>() where T : class;
13         IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda) where T : class;
14         IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda, int pageSize, int pageIndex, out int count) where T : class;
15         IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class;
16         void Excute<T>(string sql, SqlParameter[] parameters) where T : class;
17         int Commit();
18         Task<int> CommitAsync();
19 
20     }
View Code

  2、用EF实现数据访问层接口  

  1 public abstract class EntityService : IBaseService
  2     {
  3         protected DbContext DBContext { get; private set; }
  4         public EntityService(DbContext dbContext)
  5         {
  6             this.DBContext = dbContext;
  7         }
  8         public T FindEntity<T>(int id) where T : class
  9         {
 10             T entity = this.DBContext.Set<T>().Find(id);
 11             return entity;
 12         }
 13         public void AddEntity<T>(T entity) where T : class
 14         {
 15             this.DBContext.Entry(entity).State = EntityState.Added;
 16         }
 17 
 18         [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
 19         public Task<int> AddEntities<T>(IEnumerable<T> entities) where T : class
 20         {
 21             this.DBContext.Set<T>().AddRange(entities);
 22             return this.CommitAsync();
 23         }
 24         public void UpdateEntity<T>(T entity) where T : class
 25         {
 26             this.DBContext.Entry(entity).State = EntityState.Modified;
 27             //this.DBContext.Set<T>().Attach(entity);            
 28             //this.DBContext.Entry(entity).Property("")
 29         }
 30 
 31         [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
 32         public Task<int> UpdateEntities<T>(IEnumerable<T> entities) where T : class
 33         {
 34             this.DBContext.Configuration.AutoDetectChangesEnabled = false;
 35             foreach (var entity in entities)
 36             {
 37                 this.DBContext.Entry(entity).State = EntityState.Modified;
 38             }
 39             this.DBContext.Configuration.AutoDetectChangesEnabled = true;
 40             //this.DBContext.Entry(entities).State= EntityState.Modified;
 41             return this.CommitAsync();
 42         }
 43         public void DeleteEntity<T>(int id) where T : class
 44         {
 45 
 46             T entity = this.DBContext.Set<T>().Find(id);
 47             this.DBContext.Set<T>().Remove(entity);
 48         }
 49         public void DeleteEntity<T>(T entity) where T : class
 50         {
 51             this.DBContext.Set<T>().Attach(entity);
 52             this.DBContext.Entry(entity).State = EntityState.Deleted;
 53         }
 54 
 55         [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
 56         public Task<int> DeleteEntities<T>(IEnumerable<T> entities) where T : class
 57         {            
 58             //this.DBContext.Configuration.AutoDetectChangesEnabled = false;
 59             //foreach (var entity in entities)
 60             //{
 61             //    this.DBContext.Entry(entity).State = EntityState.Deleted;
 62             //}            
 63             //this.DBContext.Configuration.AutoDetectChangesEnabled = true;
 64             this.DBContext.Set<T>().RemoveRange(entities);
 65             return this.CommitAsync();
 66         }
 67 
 68         [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
 69         public Task<int> DeleteEntities<T>(Func<T, bool> whereLambda) where T : class
 70         {
 71             IQueryable<T> entities = this.DBContext.Set<T>().Where(whereLambda).AsQueryable();
 72             //this.DBContext.Entry(entities).State = EntityState.Deleted;
 73             this.DBContext.Set<T>().RemoveRange(entities);
 74             return this.CommitAsync();
 75         }
 76         public IQueryable<T> LoadEntities<T>() where T : class
 77         {
 78             return this.DBContext.Set<T>();
 79         }
 80         public IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda) where T : class
 81         {
 82             return this.DBContext.Set<T>().Where<T>(whereLambda).AsQueryable();
 83         }
 84         public IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda, int pageSize, int pageIndex, out int count) where T : class
 85         {
 86             count = 0;
 87             count = this.DBContext.Set<T>().Where(whereLambda).AsQueryable().Count();
 88             //return this.DBContext.Set<T>().Where<T>(whereLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsQueryable();
 89             return this.DBContext.Set<T>().Where(whereLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsQueryable();
 90         }
 91 
 92         #region
 93         public virtual int Commit()
 94         {
 95             return this.DBContext.SaveChanges();
 96         }
 97         public virtual Task<int> CommitAsync()
 98         {
 99             return this.DBContext.SaveChangesAsync();
100         }
101         #endregion
102         public virtual void Dispose()
103         {
104             if (this.DBContext!=null)
105             {
106                 this.DBContext.Dispose();
107             }            
108         }
109 
110         public IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class
111         {
112             return this.DBContext.Database.SqlQuery<T>(sql, parameters).AsQueryable();
113         }
114 
115         public void Excute<T>(string sql, SqlParameter[] parameters) where T : class
116         {
117             DbContextTransaction trans = null;
118             try
119             {
120                 trans = this.DBContext.Database.BeginTransaction();
121                 this.DBContext.Database.ExecuteSqlCommand(sql, parameters);
122                 trans.Commit();
123             }
124             catch (Exception ex)
125             {
126                 if (trans != null)
127                     trans.Rollback();
128                 throw ex;
129             }
130         }
131     }
View Code

二、封装Unity容器对象  

 1  public class ContainerFactory
 2     {
 3         private static IUnityContainer _iUnityContainer = null;
 4         private ContainerFactory()
 5         {
 6 
 7         }
 8         static ContainerFactory()
 9         {
10             ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
11             fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config.xml");//找配置文件的路径
12             Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
13             UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
14 
15             _iUnityContainer = new UnityContainer();
16             section.Configure(_iUnityContainer, "TestContainer");
17         }
18 
19         public static IUnityContainer GetContainerInstance()
20         {
21             return _iUnityContainer;
22         }
23     }
View Code

  上面使用静态对象方式读取Unity的配置文件并返回Unity的容器对象,方便其他对象使用。

三、示例

  1、用Code First初始化DB

    1.1、Models    

 1 [TableAttribute("Base_Sys_User")]
 2     public class User
 3     {
 4         [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
 5         public int ID { get; set; }
 6 
 7         [Column("Account")]
 8         [StringLength(50)]
 9         public String Code { get; set; }
10 
11         [StringLength(20)]
12         public String Name { get; set; }
13 
14         public Int16? Status { get; set; }
15         public DateTime CreateTime { get; set; }
View Code

    1.2、填充数据

 1 public class DataInitEF :DropCreateDatabaseIfModelChanges<DAL.DBContext.DBContext>
 2     {
 3         protected override void Seed(DAL.DBContext.DBContext context)
 4         {
 5             #region
 6             SByte? status = 1;
 7             User userEntity = new User()
 8             {
 9                 Code = "admin",
10                 Name = "管理员",
11                 Status = status,
12                 CreateTime = DateTime.Now
13             };
14 
15             List<User> users = new List<User>();
16 
17             for (int i = 1; i <= 1000; i++)
18             {
19                 if (i % 7 == 0)
20                 {
21                     status = 2;
22                 }
23                 else if (i % 17 == 0)
24                 {
25                     status = 3;
26                 }
27                 else if (i % 27 == 0)
28                 {
29                     status = -1;
30                 }
31                 else
32                 {
33                     status = 1;
34                 }
35                 users.Add(new User()
36                 {
37                     Code = "user_" + i,
38                     Name = "user_" + i,
39                     Status = status,
40                     CreateTime=DateTime.Now
41                 });
42             }
43             context.User.Add(userEntity);
44             context.User.AddRange(users);
45             #endregion
46 
47             base.Seed(context);
48         }
49 
50     }
View Code

  2、封装Model服务对象  

 1 public interface IUserService: IBaseService
 2     {        
 3         UserPayResult Pay( string userAccount, decimal? payment);
 4     }
 5 
 6     public class UserService : EntityService, IUserService
 7     {
 8         [InjectionConstructor]//构造函数注入
 9         public UserService(DbContext dbContext) : base(dbContext)
10         {
11 
12         }
13 
14       
15         public UserPayResult Pay( string userAccount, decimal? payment)
16         {
17             UserPayResult result = null;
18             if (!string.IsNullOrEmpty(userAccount))
19             {
20                 result = new UserPayResult()
21                 {
22                     UserAccount = userAccount,
23                     Message = string.Format("{0}:本次成功消费{1}元!", userAccount, payment),
24                     Status = 200,
25                     RecTimeSpan = DateTime.Now
26                 };
27             }
28             else
29             {
30                 result = new UserPayResult()
31                 {
32                     UserAccount = userAccount,
33                     Message = "支付对象余额不足!",
34                     Status = 500,
35                     RecTimeSpan = DateTime.Now
36                 };
37             }
38             return result;
39         }
40     }
View Code

上面封装了User的服务对象,并提供了接口的实现。

  3、测试  

 1  static void UserTest()
 2         {
 3             {
 4                 IUnityContainer unityContainer = ContainerFactory.GetContainerInstance();
 5 
 6               
 7                 IUserService userService = unityContainer.Resolve<IUserService>();
 8 
 9                 int inflCount = 0;
10                 var listUser = userService.LoadEntities<User>();
11                 inflCount = listUser.Count();
12                 
13 
14                 userService.Dispose();
15             }
16         }
View Code

可以看到上面并没有具体的细节对象,使用的IUserService接口是通过容器注入的UserService对象,而UserService对象则继承了EntityService对象。这些注入动作通过ContainerFactory对象读取配置文件就已经完成。

四、配置文件

<configuration>
  <configSections>
  <!--configSections节点必须放在首位-->
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
  </configSections>
  <unity>
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension,Unity.Interception.Configuration"/>
    
    <containers>
      <container name="TestContainer">
        <!--AOP扩展-->
        <extension type="Interception"/>
        <!-- 完整的类型名称,程序集名称 -->
        <register type="System.Data.Entity.DbContext, EntityFramework" mapTo="DAL.DBContext.DBContext,DAL"  />
        <register type="DAL.Service.Interface.IBaseService, DAL" mapTo="DAL.Service.Class.EntityService, DAL" name="DAL.Service.Class.EntityService" />
        <register type="UI.Console.UI.Test.IUserService, UI.Console" mapTo="UI.Console.UI.Test.UserService, UI.Console"  >
          <interceptor type="InterfaceInterceptor"/><!--只能对接口做拦截,好处是只要目标类型实现了指定接口就可以拦截-->
          <interceptionBehavior type="Common.AOP.ExceptionLoggingBehavior, Common"/>             
          <lifetime type="transient" /><!--生命周期-->
          <constructor>
            <!--构造函数参数-->
            <param name="dbContext" type="System.Data.Entity.DbContext, EntityFramework"/>
          </constructor>
        </register>
      </container>
     
    </containers>
  
  </unity>
</configuration>
View Code

配置文件格式:<register type="需要注入的类型, 程序集" mapTo="被注入的类型, 程序集"  />

五、AOP实现 

 1 namespace Common.AOP
 2 {
 3     /// <summary>
 4     /// Unity为我们提供了一个IInterceptionBehavior接口需要实现这个接口
 5     /// 接口为我们提供了三个方式(GetRequiredInterfaces、Invoke、WillExecute)实现
 6     /// WillExecute表示是否执行该行为,如果是false这个方法被调用时,不会被捕捉。因为我们总是要执行的,所以为true
 7     /// GetRequiredInterfaces将你想要的接口类型和行为联系起来,我们暂时不需要,所以返回Type.EmptyTypes
 8     /// Invoke执行方式接口
 9     /// </summary>
10     public class ExceptionLoggingBehavior : IInterceptionBehavior
11     {
12         public bool WillExecute
13         {
14             get { return true; }
15         }
16 
17         public IEnumerable<Type> GetRequiredInterfaces()
18         {
19             return Type.EmptyTypes;
20         }
21 
22         /// <summary>
23         /// 拦截函数
24         /// </summary>
25         /// <param name="input"></param>
26         /// <param name="getNext"></param>
27         /// <returns></returns>
28         public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
29         {
30             string info = string.Empty;
31             info = string.Format("当前函数对象:{0},返回类型:{1}", input.MethodBase.Name, ((MethodInfo)(input.MethodBase)).ReturnType.FullName);
32 
33             try
34             {
35                 var methodReturn = getNext().Invoke(input, getNext);
36                 if (methodReturn.Exception != null)
37                 {
38                     info += string.Format(" 执行失败:{0}", methodReturn.Exception.Message);
39                 }
40                 else
41                 {
42                     info += string.Format(" 执行成功!");
43                 }
44 
45                 Console.WriteLine(info);
46 
47                 return methodReturn;
48             }
49             catch (Exception ex)
50             {
51                 info += string.Format(" 执行失败:{0}", ex.Message);
52                 Console.WriteLine(info);
53                 throw ex;
54             }
55         }
56     }
57 }
View Code

上面的配置文件中为IUserService接口注入了UserService对象,并且配置AOP对象,所以每当调用UserService对象的方法都会被ExceptionLoggingBehavior对象拦截。

 

 

 

  

posted @ 2018-09-18 18:24  Kaden  阅读(1316)  评论(0编辑  收藏  举报