原文链接:https://www.cnblogs.com/hua66/p/9670639.html
Unity作为Microsoft推出IOC容器,其功能是非常丰富的,其中需要注意的地方也不少。以下是个人在项目中使用Unity的场景并附实例。
一、封装数据访问层
1、定义对象与DB交互接口
public interface IBaseService : IDisposable
{
T FindEntity<T>(int id) where T : class;
void AddEntity<T>(T entity) where T : class;
Task<int> AddEntities<T>(IEnumerable<T> entities) where T : class;
void UpdateEntity<T>(T entity) where T : class;
Task<int> UpdateEntities<T>(IEnumerable<T> entities) where T : class;
void DeleteEntity<T>(int id) where T : class;
void DeleteEntity<T>(T entity) where T : class;
Task<int> DeleteEntities<T>(IEnumerable<T> entities) where T : class;
Task<int> DeleteEntities<T>(Func<T, bool> whereLambda) where T : class;
IQueryable<T> LoadEntities<T>() where T : class;
IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda) where T : class;
IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda, int pageSize, int pageIndex, out int count) where T : class;
IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class;
void Excute<T>(string sql, SqlParameter[] parameters) where T : class;
int Commit();
Task<int> CommitAsync(); }
2、用EF实现数据访问层接口
public abstract class EntityService : IBaseService
{
protected DbContext DBContext { get; private set; }
public EntityService(DbContext dbContext)
{
this.DBContext = dbContext;
}
public T FindEntity<T>(int id) where T : class
{
T entity = this.DBContext.Set<T>().Find(id);
return entity;
}
public void AddEntity<T>(T entity) where T : class
{
this.DBContext.Entry(entity).State = EntityState.Added;
} [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
public Task<int> AddEntities<T>(IEnumerable<T> entities) where T : class
{
this.DBContext.Set<T>().AddRange(entities);
return this.CommitAsync();
}
public void UpdateEntity<T>(T entity) where T : class
{
this.DBContext.Entry(entity).State = EntityState.Modified;
//this.DBContext.Set<T>().Attach(entity);
//this.DBContext.Entry(entity).Property("")
} [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
public Task<int> UpdateEntities<T>(IEnumerable<T> entities) where T : class
{
this.DBContext.Configuration.AutoDetectChangesEnabled = false;
foreach (var entity in entities)
{
this.DBContext.Entry(entity).State = EntityState.Modified;
}
this.DBContext.Configuration.AutoDetectChangesEnabled = true;
//this.DBContext.Entry(entities).State= EntityState.Modified;
return this.CommitAsync();
}
public void DeleteEntity<T>(int id) where T : class
{ T entity = this.DBContext.Set<T>().Find(id);
this.DBContext.Set<T>().Remove(entity);
}
public void DeleteEntity<T>(T entity) where T : class
{
this.DBContext.Set<T>().Attach(entity);
this.DBContext.Entry(entity).State = EntityState.Deleted;
} [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
public Task<int> DeleteEntities<T>(IEnumerable<T> entities) where T : class
{
//this.DBContext.Configuration.AutoDetectChangesEnabled = false;
//foreach (var entity in entities)
//{
// this.DBContext.Entry(entity).State = EntityState.Deleted;
//}
//this.DBContext.Configuration.AutoDetectChangesEnabled = true;
this.DBContext.Set<T>().RemoveRange(entities);
return this.CommitAsync();
} [Obsolete("不建议使用基于EF实现批量操作函数,此操作已异步提交!", false)]
public Task<int> DeleteEntities<T>(Func<T, bool> whereLambda) where T : class
{
IQueryable<T> entities = this.DBContext.Set<T>().Where(whereLambda).AsQueryable();
//this.DBContext.Entry(entities).State = EntityState.Deleted;
this.DBContext.Set<T>().RemoveRange(entities);
return this.CommitAsync();
}
public IQueryable<T> LoadEntities<T>() where T : class
{
return this.DBContext.Set<T>();
}
public IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda) where T : class
{
return this.DBContext.Set<T>().Where<T>(whereLambda).AsQueryable();
}
public IQueryable<T> LoadEntities<T>(Func<T, bool> whereLambda, int pageSize, int pageIndex, out int count) where T : class
{
count = ;
count = this.DBContext.Set<T>().Where(whereLambda).AsQueryable().Count();
//return this.DBContext.Set<T>().Where<T>(whereLambda).Skip((pageIndex - 1) * pageSize).Take(pageSize).AsQueryable();
return this.DBContext.Set<T>().Where(whereLambda).Skip((pageIndex - ) * pageSize).Take(pageSize).AsQueryable();
} #region
public virtual int Commit()
{
return this.DBContext.SaveChanges();
}
public virtual Task<int> CommitAsync()
{
return this.DBContext.SaveChangesAsync();
}
#endregion
public virtual void Dispose()
{
if (this.DBContext!=null)
{
this.DBContext.Dispose();
}
} public IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class
{
return this.DBContext.Database.SqlQuery<T>(sql, parameters).AsQueryable();
} public void Excute<T>(string sql, SqlParameter[] parameters) where T : class
{
DbContextTransaction trans = null;
try
{
trans = this.DBContext.Database.BeginTransaction();
this.DBContext.Database.ExecuteSqlCommand(sql, parameters);
trans.Commit();
}
catch (Exception ex)
{
if (trans != null)
trans.Rollback();
throw ex;
}
}
}
二、封装Unity容器对象
public class ContainerFactory
{
private static IUnityContainer _iUnityContainer = null;
private ContainerFactory()
{ }
static ContainerFactory()
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config.xml");//找配置文件的路径
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); _iUnityContainer = new UnityContainer();
section.Configure(_iUnityContainer, "TestContainer");
} public static IUnityContainer GetContainerInstance()
{
return _iUnityContainer;
}
}
上面使用静态对象方式读取Unity的配置文件并返回Unity的容器对象,方便其他对象使用。
三、示例
1、用Code First初始化DB
1.1、Models
[TableAttribute("Base_Sys_User")]
public class User
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; } [Column("Account")]
[StringLength()]
public String Code { get; set; } [StringLength()]
public String Name { get; set; } public Int16? Status { get; set; }
public DateTime CreateTime { get; set; }
1.2、填充数据
public class DataInitEF :DropCreateDatabaseIfModelChanges<DAL.DBContext.DBContext>
{
protected override void Seed(DAL.DBContext.DBContext context)
{
#region
SByte? status = ;
User userEntity = new User()
{
Code = "admin",
Name = "管理员",
Status = status,
CreateTime = DateTime.Now
}; List<User> users = new List<User>(); for (int i = ; i <= ; i++)
{
if (i % == )
{
status = ;
}
else if (i % == )
{
status = ;
}
else if (i % == )
{
status = -;
}
else
{
status = ;
}
users.Add(new User()
{
Code = "user_" + i,
Name = "user_" + i,
Status = status,
CreateTime=DateTime.Now
});
}
context.User.Add(userEntity);
context.User.AddRange(users);
#endregion base.Seed(context);
} }
2、封装Model服务对象
public interface IUserService: IBaseService
{
UserPayResult Pay( string userAccount, decimal? payment);
} public class UserService : EntityService, IUserService
{
[InjectionConstructor]//构造函数注入
public UserService(DbContext dbContext) : base(dbContext)
{ } public UserPayResult Pay( string userAccount, decimal? payment)
{
UserPayResult result = null;
if (!string.IsNullOrEmpty(userAccount))
{
result = new UserPayResult()
{
UserAccount = userAccount,
Message = string.Format("{0}:本次成功消费{1}元!", userAccount, payment),
Status = ,
RecTimeSpan = DateTime.Now
};
}
else
{
result = new UserPayResult()
{
UserAccount = userAccount,
Message = "支付对象余额不足!",
Status = ,
RecTimeSpan = DateTime.Now
};
}
return result;
}
}
上面封装了User的服务对象,并提供了接口的实现。
3、测试
static void UserTest()
{
{
IUnityContainer unityContainer = ContainerFactory.GetContainerInstance(); IUserService userService = unityContainer.Resolve<IUserService>(); int inflCount = ;
var listUser = userService.LoadEntities<User>();
inflCount = listUser.Count(); userService.Dispose();
}
}
可以看到上面并没有具体的细节对象,使用的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>
配置文件格式:<register type="需要注入的类型, 程序集" mapTo="被注入的类型, 程序集" />
五、AOP实现
namespace Common.AOP
{
/// <summary>
/// Unity为我们提供了一个IInterceptionBehavior接口需要实现这个接口
/// 接口为我们提供了三个方式(GetRequiredInterfaces、Invoke、WillExecute)实现
/// WillExecute表示是否执行该行为,如果是false这个方法被调用时,不会被捕捉。因为我们总是要执行的,所以为true
/// GetRequiredInterfaces将你想要的接口类型和行为联系起来,我们暂时不需要,所以返回Type.EmptyTypes
/// Invoke执行方式接口
/// </summary>
public class ExceptionLoggingBehavior : IInterceptionBehavior
{
public bool WillExecute
{
get { return true; }
} public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} /// <summary>
/// 拦截函数
/// </summary>
/// <param name="input"></param>
/// <param name="getNext"></param>
/// <returns></returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
string info = string.Empty;
info = string.Format("当前函数对象:{0},返回类型:{1}", input.MethodBase.Name, ((MethodInfo)(input.MethodBase)).ReturnType.FullName); try
{
var methodReturn = getNext().Invoke(input, getNext);
if (methodReturn.Exception != null)
{
info += string.Format(" 执行失败:{0}", methodReturn.Exception.Message);
}
else
{
info += string.Format(" 执行成功!");
} Console.WriteLine(info); return methodReturn;
}
catch (Exception ex)
{
info += string.Format(" 执行失败:{0}", ex.Message);
Console.WriteLine(info);
throw ex;
}
}
}
}
上面的配置文件中为IUserService接口注入了UserService对象,并且配置AOP对象,所以每当调用UserService对象的方法都会被ExceptionLoggingBehavior对象拦截。