回到目錄
說在前
Ioc元件有很多,之前也介紹過autofac,castle等,今天再來說一下在微軟Nlayer DDD架構裡使用的unity元件,今天主要說一下依靠注入,如果希望看攔截的用法,可以閱讀這篇文章第十三回 實作AOP的攔截元件Unity.Interception
做在後
unity的用法主要說一下接口注入方法,它包括了程式中注入和配置檔案注入,而接口注入還分為普通接口注入和泛型接口注入,下面分别來說一下:
普通接口和類實作代碼
public interface IUser
{
IQueryable<WebManageUsers> GetEntities();
}
public class UserRepository : BackgroundRepository<WebManageUsers>, IUser
{
public IQueryable<WebManageUsers> GetEntities()
{
return this.GetModel();
}
}
普通接口注入,程式中的注入
using (IUnityContainer container = new UnityContainer())
{
container.RegisterType<IUser, DataTest.UserRepository>();
var repository = container.Resolve<IUser>();
}
普通接口注入,配置檔案中的注入
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="EntityTest.IUser,EntityTest" mapTo="DataTest.UserRepository, DataTest" />
</container>
</unity>
using (IUnityContainer container = new UnityContainer())
{
ConfigurationManager.GetSection("unity");
UnityConfigurationSection.CurrentSection.Configure(container);
var repository = container.Resolve<IUser>();
}
/// <summary>
/// 基礎的資料操作規範
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public interface IRepository<TEntity>
where TEntity : class
{
/// <summary>
/// 添加實體并送出到資料伺服器
/// </summary>
/// <param name="item">Item to add to repository</param>
void Insert(TEntity item);
/// <summary>
/// 移除實體并送出到資料伺服器
/// 如果表存在限制,需要先删除子表資訊
/// </summary>
/// <param name="item">Item to delete</param>
void Delete(TEntity item);
/// <summary>
/// 修改實體并送出到資料伺服器
/// </summary>
/// <param name="item"></param>
void Update(TEntity item);
/// <summary>
/// 得到指定的實體集合(延時結果集)
/// Get all elements of type {T} in repository
/// </summary>
/// <returns>List of selected elements</returns>
IQueryable<TEntity> GetModel();
/// <summary>
/// 根據主鍵得到實體
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
TEntity Find(params object[] id);
}
public class BackgroundRepository<T> : IRepository<T> where T : class
{
#region IRepository<TEntity> 成員
public virtual void Insert(TEntity item)
{
OnBeforeSaved(new SavedEventArgs(item, SaveAction.Insert));
Db.Entry<TEntity>(item);
Db.Set<TEntity>().Add(item);
this.SaveChanges();
OnAfterSaved(new SavedEventArgs(item, SaveAction.Insert));
}
public virtual void Delete(TEntity item)
{
OnBeforeSaved(new SavedEventArgs(item, SaveAction.Delete));
Db.Set<TEntity>().Attach(item);
Db.Set<TEntity>().Remove(item);
this.SaveChanges();
OnAfterSaved(new SavedEventArgs(item, SaveAction.Delete));
}
public virtual void Update(TEntity item)
{
OnBeforeSaved(new SavedEventArgs(item, SaveAction.Update));
Db.Set<TEntity>().Attach(item);
Db.Entry(item).State = EntityState.Modified;
this.SaveChanges();
OnAfterSaved(new SavedEventArgs(item, SaveAction.Update));
}
/// <summary>
/// 子類在實作時,可以重寫,加一些狀态過濾
/// </summary>
/// <returns></returns>
public virtual IQueryable<TEntity> GetModel()
{
// return Db.Set<TEntity>().AsNoTracking();//對象無法自動添加到上下文中,因為它是使用 NoTracking 合并選項檢索的。請在定義此關系之前,将該實體顯式附加到 ObjectContext。
return Db.Set<TEntity>();////ObjectStateManager 中已存在具有同一鍵的對象。ObjectStateManager 無法跟蹤具有相同鍵的多個對象。
}
/// <summary>
/// 得到原生态結果集
/// </summary>
/// <returns></returns>
public IQueryable<TEntity> GetEntities()
{
return Db.Set<TEntity>();
}
#endregion
}
泛型接口注入,程式中的注入
using (IUnityContainer container = new UnityContainer())
{
container.RegisterType<IRepository<User>, BackgroundRepository<User>>();
var re = container.Resolve<IRepository<User>>();
}
泛型接口注入,配置檔案中的注入
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="IRepository.Core.IRepository`1,IRepository.Core" mapTo="DataTest.BackgroundRepository`1, DataTest" />
</container>
</unity>
using (IUnityContainer container = new UnityContainer())
{
ConfigurationManager.GetSection("unity");
UnityConfigurationSection.CurrentSection.Configure(container);
var re = container.Resolve<IRepository<User>>();
}
下面我們封裝一個服務定位器,讓它把Unity容器封裝一下,友善以後調用它,下面是ServiceLocator的原代碼:
/// <summary>
/// Represents the Service Locator.
/// </summary>
public sealed class ServiceLocator : IServiceProvider
{
#region Private Fields
private readonly IUnityContainer _container;
#endregion
#region Private Static Fields
private static readonly ServiceLocator instance = new ServiceLocator();
#endregion
#region Ctor
/// <summary>
/// Initializes a new instance of ServiceLocator class.
/// </summary>
private ServiceLocator()
{
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
_container = new UnityContainer();
section.Configure(_container);
}
#endregion
#region Public Static Properties
/// <summary>
/// Gets the singleton instance of the ServiceLocator class.
/// </summary>
public static ServiceLocator Instance
{
get { return instance; }
}
#endregion
#region Private Methods
private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments)
{
List<ParameterOverride> overrides = new List<ParameterOverride>();
Type argumentsType = overridedArguments.GetType();
argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToList()
.ForEach(property =>
{
var propertyValue = property.GetValue(overridedArguments, null);
var propertyName = property.Name;
overrides.Add(new ParameterOverride(propertyName, propertyValue));
});
return overrides;
}
#endregion
#region Public Methods
/// <summary>
/// Gets the service instance with the given type.
/// </summary>
/// <typeparam name="T">The type of the service.</typeparam>
/// <returns>The service instance.</returns>
public T GetService<T>()
{
return _container.Resolve<T>();
}
/// <summary>
/// Gets the service instance with the given type by using the overrided arguments.
/// </summary>
/// <typeparam name="T">The type of the service.</typeparam>
/// <param name="overridedArguments">The overrided arguments.</param>
/// <returns>The service instance.</returns>
public T GetService<T>(object overridedArguments)
{
var overrides = GetParameterOverrides(overridedArguments);
return _container.Resolve<T>(overrides.ToArray());
}
/// <summary>
/// Gets the service instance with the given type by using the overrided arguments.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <param name="overridedArguments">The overrided arguments.</param>
/// <returns>The service instance.</returns>
public object GetService(Type serviceType, object overridedArguments)
{
var overrides = GetParameterOverrides(overridedArguments);
return _container.Resolve(serviceType, overrides.ToArray());
}
#endregion
#region IServiceProvider Members
/// <summary>
/// Gets the service instance with the given type.
/// </summary>
/// <param name="serviceType">The type of the service.</param>
/// <returns>The service instance.</returns>
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
#endregion
}
下面再去使用unity時就友善多了,呵呵,看代碼:
var model = ServiceLocator.Instance.GetService<IExtensionRepository<WebManageUsers>>().GetModel().ToList();
而使用ServiceLocator還有一個好處,就是不需要使用"實作的程式集",隻要把"實作的程式集"和它的相關依賴的程式集一起複制到WEB項目的BIN目錄即可,服務定位器會自己去定位的.
好了,講到這裡也就差不多了,需要注意的是,如果你在項目中進行注入時,需要先注入的實作類所在的程式集也引入進來,否則也是不可以resolve出來對象的,而對于業務層(領域)層來說,不需要關心底層
的實作技術,即不需要引用實作類的程式集,而在業務層引用接口程式集即可.
回到目錄
作者:倉儲大叔,張占嶺,
榮譽:微軟MVP
QQ:853066980
支付寶掃一掃,為大叔打賞!
