服務層代碼
首先我先放出2個主要類的代碼再分別講解
接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Coralcode.Framework.Models;
using Coralcode.Framework.Page;
namespace Coralcode.Framework.Services
{
/// <summary>
/// 全功能增刪改查服務
/// </summary>
/// <typeparam name="TModel"></typeparam>
/// <typeparam name="TSearch"></typeparam>
/// <typeparam name="TOrder"></typeparam>
public interface ICrudCoralService<TModel, in TSearch, in TOrder> : IServiceWithContext
where TModel : class, IViewModel, new()
where TSearch : SearchBase
where TOrder : OrderBase
{
TModel Get(long id);
void Create(TModel model);
void Create(List<TModel> models);
void Modify(TModel model);
void Modify(List<TModel> model);
void Remove(long id);
void Remove(List<long> ids);
List<TModel> GetAll();
List<TModel> Search(TSearch search);
PagedList<TModel> PageSearch(PageInfo page, TSearch search, TOrder order);
}
/// <summary>
/// 默認排序的增刪改查服務
/// </summary>
/// <typeparam name="TModel"></typeparam>
/// <typeparam name="TSearch"></typeparam>
public interface ICrudCoralService<TModel, in TSearch> : ICrudCoralService<TModel, TSearch, OrderBase>
where TModel : class, IViewModel, new()
where TSearch : SearchBase
{
}
/// <summary>
/// 默認查詢的增刪改查服務
/// </summary>
/// <typeparam name="TModel"></typeparam>
public interface ICrudCoralService<TModel> : ICrudCoralService<TModel, SearchBase, OrderBase>
where TModel : class, IViewModel, new()
{
}
}
實現
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Coralcode.Framework.Aspect.Unity;
using Coralcode.Framework.Data.Repository;
using Coralcode.Framework.Data.Repository.Core;
using Coralcode.Framework.Data.Specification;
using Coralcode.Framework.Domains;
using Coralcode.Framework.Exceptions;
using Coralcode.Framework.Mapper;
using Coralcode.Framework.MessageBus.Event;
using Coralcode.Framework.MessageBus.EventHandlers.Entities;
using Coralcode.Framework.Models;
using Coralcode.Framework.Page;
using EmitMapper.MappingConfiguration;
namespace Coralcode.Framework.Services
{
public abstract class CrudCoralService<TEntity, TModel, TSearch, TOrder> : CoralService, ICrudCoralService<TModel, TSearch, TOrder>
where TEntity : Entity, new()
where TModel : class, IViewModel, new()
where TSearch : SearchBase
where TOrder : OrderBase
{
protected IRepository<TEntity> Repository;
/// <summary>
/// 這里為了隱藏事件總線這一復雜東西
/// </summary>
protected IEventBus EventBus;
protected CrudCoralService(IRepository<TEntity> repository, IEventBus eventBus)
{
Repository = repository;
EventBus = eventBus;
}
public virtual TModel Get(long id)
{
var entity = Repository.Get(id);
if (entity == null)
return null;
return Convert(entity);
}
public virtual void Create(TModel model)
{
var entity = Convert(model);
entity.Id = model.Id;
Repository.Add(entity);
model.Id = entity.Id;
Repository.UnitOfWork.Commit();
EventBus.Publish(new EntityCreatedEventData<TModel>(model));
}
public virtual void Create(List<TModel> models)
{
models.ForEach(model =>
{
var entity = Convert(model);
Repository.Add(entity);
model.Id = entity.Id;
});
Repository.UnitOfWork.Commit();
models.ForEach(model =>
{
EventBus.Publish(new EntityCreatedEventData<TModel>(model));
});
}
public virtual void Modify(TModel model)
{
var entity = Repository.Get(model.Id);
if (entity == null)
throw new NotFoundException("實體沒有找到");
var oldModel = Convert(entity);
Convert(model, entity);
Repository.Modify(entity);
Repository.UnitOfWork.Commit();
EventBus.Publish(new EntityModifyEventData<TModel>(model, oldModel));
}
public void Modify(List<TModel> models)
{
var items = new List<KeyValuePair<TModel, TModel>>();
models.ForEach(model =>
{
var entity = Repository.Get(model.Id);
if (entity == null)
return;
var oldModel = Convert(entity);
items.Add(new KeyValuePair<TModel, TModel>(model, oldModel));
Convert(model, entity);
Repository.Modify(entity);
Repository.UnitOfWork.Commit();
});
Repository.UnitOfWork.Commit();
items.ForEach(item =>
{
EventBus.Publish(new EntityModifyEventData<TModel>(item.Key, item.Value));
});
}
public virtual void Remove(long id)
{
var item = Get(id);
if (item == null)
return;
Repository.Remove(id);
Repository.UnitOfWork.Commit();
EventBus.Publish(new EntityRemoveEventData<TModel>(item));
}
public virtual void Remove(List<long> ids)
{
var items = new List<TModel>();
ids.ForEach(id =>
{
items.Add(Get(id));
Repository.Remove(id);
});
Repository.UnitOfWork.Commit();
items.ForEach(item =>
{
EventBus.Publish(new EntityRemoveEventData<TModel>(item));
});
}
public virtual List<TModel> GetAll()
{
return Repository.GetAll().Select(Convert).ToList();
}
public virtual List<TModel> Search(TSearch search)
{
return Repository.GetAllMatching(GetFilter(search)).Select(Convert).ToList();
}
public PagedList<TModel> PageSearch(PageInfo page, TSearch search, TOrder order)
{
return Repository.GetPaged(page.PageIndex, page.PageSize, GetFilter(search),new SortExpression<TEntity>(GetOrder(order))).ConvertToPagedList(Convert);
}
protected virtual ISpecification<TEntity> GetFilter(TSearch search)
{
return new DirectSpecification<TEntity>(item => item.Id > 0);
}
protected virtual List<EditableKeyValuePair<Expression<Func<TEntity, dynamic>>, bool>> GetOrder(TOrder order)
{
return new List<EditableKeyValuePair<Expression<Func<TEntity, dynamic>>, bool>>
{
new EditableKeyValuePair<Expression<Func<TEntity, dynamic>>, bool>(item=>item.Id,true),
};
}
/// <summary>
/// 出來轉換
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
protected virtual TModel Convert(TEntity entity)
{
return DataMapperProvider.Mapper.Convert<TEntity, TModel>(entity);
}
/// <summary>
/// 進入轉換
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
protected virtual TEntity Convert(TModel model)
{
return DataMapperProvider.Mapper.Convert<TModel, TEntity>(model, new DefaultMapConfig().IgnoreMembers<TModel, TEntity>(new[] { "Id" }));
}
/// <summary>
/// 屬性賦值
/// </summary>
/// <param name="model"></param>
/// <param name="entity"></param>
protected virtual void Convert(TModel model, TEntity entity)
{
DataMapperProvider.Mapper.Convert(model, entity, new DefaultMapConfig().IgnoreMembers<TModel, TEntity>(new[] { "Id" }));
}
}
public abstract class CrudCoralService<TEntity, TModel, TSearch> : CrudCoralService<TEntity, TModel, TSearch, OrderBase>
where TEntity : Entity, new()
where TModel : class, IViewModel, new()
where TSearch : SearchBase
{
protected CrudCoralService(IRepository<TEntity> repository, IEventBus eventBus) : base(repository, eventBus)
{
}
}
public abstract class CrudCoralService<TEntity, TModel> : CrudCoralService<TEntity, TModel, SearchBase, OrderBase>
where TEntity : Entity, new()
where TModel : class, IViewModel, new()
{
protected CrudCoralService(IRepository<TEntity> repository, IEventBus eventBus) : base(repository, eventBus)
{
}
}
}
查詢實體
上一節提到Specification實現查詢功能,主要實現Where功能, 但是查詢還需要數據承載,查詢實體就是數據的承載,其中數據到 表達式或者sql的拼接就是在GetFilter中實現的,這里要注意寫法特別是 expression=expression.And(xxx).一定要賦值給自己。SearchBase只是一個泛型限制里面暫時沒有任何實現
以下是一個GetFilter實現
protected override ISpecification<PrivateLesson> GetFilter(LessonSearch search)
{
var expression = (Expression<Func<PrivateLesson, bool>>)(item => true);
if (search == null)
return base.GetFilter(null);
if (search.StartTime != default(DateTime))
expression = expression.And(item => item.StartTime > search.StartTime);
if (search.EndTime != default(DateTime))
expression = expression.And(item => item.StartTime < search.EndTime);
if (!string.IsNullOrWhiteSpace(search.Text))
expression =
expression.And(item => item.Name.Contains(search.Text) || item.Coach.Name.Contains(search.Text));
return new DirectSpecification<PrivateLesson>(expression);
}
排序實體
等同於查詢實體,排序實體也是排序功能的數據承載,OrderBase只是一個泛型限制,里面暫時沒有任何實現
泛型維度的縮放
對於上面排序和查詢的功能並不是一定都需要,所以做了維度縮放,可以從三種
維度去使用Crud的服務.
對於服務的實現上加入了模型實體(也就是和數據庫映射的模型),這么做的好處是
使用接口的人無需知道數據庫怎么存放表怎么映射,接口和實現分離。
Mapper
我們選用EmitMapper作為Entity和DTO的映射,目前來看這個性能是除了直接賦值
之外性能最好的了,網上有很多對比文章請自行參考。當然如果你不習慣也可以
換一種實現
這里代碼參考NLayerApp中Mapper的設計,略作修改
注意這里配置文件采用Dynamic的方式可以讓簡單使用的地方不需要引用EmitMapper,
除非是要做一些擴展
namespace Coralcode.Framework.Mapper
{
public class DataMapperProvider
{
public static IDataMapper Mapper
{
get { return new EmitmapperDataMapper(); }
}
}
}
namespace Coralcode.Framework.Mapper
{
public interface IDataMapper
{
TTarget Convert<TSource, TTarget>(TSource source)
where TTarget : class, new()
where TSource : class;
TTarget Convert<TSource, TTarget>(TSource source, TTarget target)
where TTarget : class
where TSource : class;
/// <summary>
/// 帶配置文件的轉換
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TTarget"></typeparam>
/// <param name="source"></param>
/// <param name="target"></param>
/// <param name="config">配置文件</param>
/// <returns></returns>
TTarget Convert<TSource, TTarget>(TSource source, TTarget target, dynamic config)
where TTarget : class
where TSource : class;
/// <summary>
/// 帶配置文件的轉換
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TTarget"></typeparam>
/// <param name="source"></param>
/// <param name="config">配置文件</param>
/// <returns></returns>
TTarget Convert<TSource, TTarget>(TSource source, dynamic config)
where TTarget : class, new()
where TSource : class;
}
}
using EmitMapper;
using EmitMapper.MappingConfiguration;
namespace Coralcode.Framework.Mapper
{
public class EmitmapperDataMapper
: IDataMapper
{
#region ITypeAdapter Members
public TTarget Convert<TSource, TTarget>(TSource source)
where TSource : class
where TTarget : class, new()
{
ObjectsMapper<TSource, TTarget> mapper =
ObjectMapperManager.DefaultInstance.GetMapper<TSource, TTarget>(new DefaultMapConfig());
return mapper.Map(source);
}
public TTarget Convert<TSource, TTarget>(TSource source, TTarget target)
where TTarget : class
where TSource : class
{
ObjectsMapper<TSource, TTarget> mapper =
ObjectMapperManager.DefaultInstance.GetMapper<TSource, TTarget>(new DefaultMapConfig());
return mapper.Map(source, target);
}
public TTarget Convert<TSource, TTarget>(TSource source, TTarget target, dynamic config)
where TTarget : class
where TSource : class
{
ObjectsMapper<TSource, TTarget> mapper =
ObjectMapperManager.DefaultInstance.GetMapper<TSource, TTarget>((DefaultMapConfig)config);
return mapper.Map(source, target);
}
public TTarget Convert<TSource, TTarget>(TSource source, dynamic config)
where TTarget : class, new()
where TSource : class
{
ObjectsMapper<TSource, TTarget> mapper =
ObjectMapperManager.DefaultInstance.GetMapper<TSource, TTarget>(config);
return mapper.Map(source);
}
#endregion
}
}
EF更新機制
EF更新這也是我經常使用的一個面試題,很多人會回答直接由Update方法可以調用
實際上ef是通過代理對象並且實現INotifyChange接口來監聽屬性的改變。
EF更新的時候不能修改主鍵的值,所以我這里做了忽略。其他屬性全部更新,
當然如果涉及到具體業務比如修改賬號或者金額之類的修改,最好是擴展服務實現
不要用這個服務中自帶的更新方法,直接使用Repository去更新
Attribute注入配置化
這里我使用Attribute做Ioc配置,其中生命周期的枚舉參考unity框架的設計,
具體怎么使用可以參考網上的文章。
實現機制是在一個用啟動的時候掃描程序集有這個標記的類型,然后讀出
RegisterType做注冊,並且支持多注冊
UnityService的代碼
注意這里Register方法最后一個參數用dynamic,這樣使用的地方就可以不依賴於Unity,
其中包含了Aop和幾個設計技巧,有問題的可以留言我再做解答
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Coralcode.Framework.Extensions;
using Coralcode.Framework.Reflection;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace Coralcode.Framework.Aspect.Unity
{
/// <summary>
/// IOC容器
/// </summary>
public class UnityService
{
static UnityService()
{
//注冊標記
Current = new UnityContainer();
Current.AddNewExtension<Interception>();
var currentType = typeof(UnityService);
var containers = new List<dynamic>();
//模塊初始化
containers.ForEach(item => item.Regist());
//模塊啟動
containers.ForEach(item => item.RegistComplete());
MetaDataManager.Type.GetAllTypes().ForEach(item =>
{
if (item == null)
return;
var registers = item.GetCustomAttributes<InjectAttribute>().ToList();
if (registers.Count == 0)
return;
registers.ForEach(register =>
{
if (register.RegisterType != null)
RegisterType(register.Name, register.RegisterType, item, GetLifetimeManager(register.LifetimeManagerType), GetInjectionMembers(register.AopType, item));
else
RegisterType(register.Name, item, GetLifetimeManager(register.LifetimeManagerType), GetInjectionMembers(register.AopType, item));
});
});
}
#region 屬性
/// <summary>
/// Get the current configured container
/// </summary>
/// <returns>Configured container</returns>
private static IUnityContainer Current { get; set; }
#endregion
/// <summary>
/// 在當前模塊中注冊接口的實現
/// </summary>
protected virtual void Regist()
{
}
/// <summary>
/// 在當前模塊中注冊應用程序啟動事件
/// </summary>
protected virtual void RegistComplete()
{
}
#region 注冊相關的方法
/// <summary>
/// 獲取生命周期
/// </summary>
/// <param name="lifetimeManagerType"></param>
/// <returns></returns>
public static LifetimeManager GetLifetimeManager(LifetimeManagerType lifetimeManagerType)
{
switch (lifetimeManagerType)
{
case LifetimeManagerType.Transient:
return new TransientLifetimeManager();
case LifetimeManagerType.ContainerControlled:
return new ContainerControlledLifetimeManager();
case LifetimeManagerType.Hierarchica:
return new HierarchicalLifetimeManager();
case LifetimeManagerType.Externally:
return new ExternallyControlledLifetimeManager();
case LifetimeManagerType.PerThread:
return new PerThreadLifetimeManager();
case LifetimeManagerType.PerResolve:
return new PerResolveLifetimeManager();
default:
return new TransientLifetimeManager();
}
}
/// <summary>
/// 注入aop方法
/// </summary>
/// <param name="aopType"></param>
/// <param name="type"></param>
/// <returns></returns>
public static InjectionMember[] GetInjectionMembers(AopType aopType, Type type)
{
var members = new List<InjectionMember>();
switch (aopType)
{
case AopType.VirtualMethodInterceptor:
members.Add(new Interceptor<VirtualMethodInterceptor>());
break;
case AopType.InterfaceInterceptor:
members.Add(new Interceptor<InterfaceInterceptor>());
break;
case AopType.TransparentProxyInterceptor:
members.Add(new Interceptor<TransparentProxyInterceptor>());
break;
}
members.AddRange(type.GetCustomAttributes()
.Where(item => item.GetType().IsSubclassOf(typeof(UnityAopAttribute)))
.Cast<UnityAopAttribute>()
.Select(item => new InterceptionBehavior(item)));
return members.ToArray();
}
#endregion
/// <summary>
/// 注冊泛型類型
/// </summary>
/// <param name="injectionMembers">構造函數參數</param>
public static void Register<TTarget, TSource>(params dynamic[] injectionMembers) where TSource : TTarget
{
RegisterType<TTarget, TSource>("",injectionMembers);
}
/// <summary>
/// 注冊泛型類型
/// </summary>
/// <param name="name"></param>
/// <param name="injectionMembers">構造函數參數</param>
public static void RegisterType<TTarget, TSource>(string name, params dynamic[] injectionMembers) where TSource : TTarget
{
var members = new List<InjectionMember>();
LinqExtensions.ForEach(injectionMembers, item =>
{
if (item is InjectionMember)
members.Add(item);
if (item is InjectionMember[])
members.AddRange(item);
else if (item is ConstructorParameter)
members.Add(new InjectionConstructor(item.Value));
else if (item is ConstructorParameter[])
members.AddRange((item as ConstructorParameter[]).Select(data => new InjectionConstructor(data.Value)));
});
var lifetimeManager = injectionMembers.OfType<LifetimeManager>().FirstOrDefault();
if (string.IsNullOrEmpty(name))
{
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType<TTarget, TSource>();
else if (lifetimeManager == null)
Current.RegisterType<TTarget, TSource>(members.ToArray());
else if (injectionMembers == null)
Current.RegisterType<TTarget, TSource>(lifetimeManager);
else
Current.RegisterType<TTarget, TSource>(lifetimeManager, members.ToArray());
}
else
{
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType<TTarget, TSource>(name);
else if (lifetimeManager == null)
Current.RegisterType<TTarget, TSource>(name, members.ToArray());
else if (injectionMembers == null)
Current.RegisterType<TTarget, TSource>(name, lifetimeManager);
else
Current.RegisterType<TTarget, TSource>(name, lifetimeManager, members.ToArray());
}
}
/// <summary>
/// 注冊類型
/// </summary>
/// <param name="source"></param>
/// <param name="target"></param>
/// <param name="lifetimeManager"></param>
/// <param name="injectionMembers"></param>
public static void RegisterType(string name, Type target, Type source, params dynamic[] injectionMembers)
{
var members = new List<InjectionMember>();
LinqExtensions.ForEach(injectionMembers, item =>
{
if (item is InjectionMember)
members.Add(item);
if (item is InjectionMember[])
members.AddRange(item);
else if (item is ConstructorParameter)
members.Add(new InjectionConstructor(item.Value));
else if (item is ConstructorParameter[])
members.AddRange((item as ConstructorParameter[]).Select(data => new InjectionConstructor(data.Value)));
});
var lifetimeManager = injectionMembers.OfType<LifetimeManager>().FirstOrDefault();
if (string.IsNullOrEmpty(name))
{
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType(target, source);
else if (lifetimeManager == null)
Current.RegisterType(target, source, members.ToArray());
else if (injectionMembers == null)
Current.RegisterType(target, source, lifetimeManager);
else
Current.RegisterType(target, source, lifetimeManager, members.ToArray());
}
else
{
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType(target, source, name);
else if (lifetimeManager == null)
Current.RegisterType(target, source, name, members.ToArray());
else if (injectionMembers == null)
Current.RegisterType(target, source, name, lifetimeManager);
else
Current.RegisterType(target, source, name, lifetimeManager, members.ToArray());
}
}
/// <summary>
/// 注冊類型
/// </summary>
/// <param name="source"></param>
/// <param name="target"></param>
/// <param name="lifetimeManager"></param>
/// <param name="injectionMembers"></param>
public static void RegisterType(Type target, Type source, params dynamic[] injectionMembers)
{
var members = new List<InjectionMember>();
LinqExtensions.ForEach(injectionMembers, item =>
{
if (item is InjectionMember)
members.Add(item);
if (item is InjectionMember[])
members.AddRange(item);
else if (item is ConstructorParameter)
members.Add(new InjectionConstructor(item.Value));
else if (item is ConstructorParameter[])
members.AddRange((item as ConstructorParameter[]).Select(data => new InjectionConstructor(data.Value)));
});
var lifetimeManager = injectionMembers.OfType<LifetimeManager>().FirstOrDefault();
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType(target, source);
else if (lifetimeManager == null)
Current.RegisterType(target, source, members.ToArray());
else if (injectionMembers == null)
Current.RegisterType(target, source, lifetimeManager);
else
Current.RegisterType(target, source, lifetimeManager, members.ToArray());
}
/// <summary>
/// 注冊類型
/// </summary>
/// <param name="injectionMembers"></param>
public static void RegisterType(Type type, params dynamic[] injectionMembers)
{
var members = new List<InjectionMember>();
LinqExtensions.ForEach(injectionMembers, item =>
{
if (item is InjectionMember)
members.Add(item);
if (item is InjectionMember[])
members.AddRange(item);
else if (item is ConstructorParameter)
members.Add(new InjectionConstructor(item.Value));
else if (item is ConstructorParameter[])
members.AddRange((item as ConstructorParameter[]).Select(data => new InjectionConstructor(data.Value)));
});
var lifetimeManager = injectionMembers.OfType<LifetimeManager>().FirstOrDefault();
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType(type);
else if (lifetimeManager == null)
Current.RegisterType(type, members.ToArray());
else if (injectionMembers == null)
Current.RegisterType(type, lifetimeManager);
else
Current.RegisterType(type, lifetimeManager, members.ToArray());
}
/// <summary>
/// 注冊類型
/// </summary>
/// <param name="type"></param>
/// <param name="injectionMembers"></param>
/// <param name="name"></param>
public static void RegisterType(string name, Type type, params dynamic[] injectionMembers)
{
var members = new List<InjectionMember>();
LinqExtensions.ForEach(injectionMembers, item =>
{
if (item is InjectionMember)
members.Add(item);
if (item is InjectionMember[])
members.AddRange(item);
else if (item is ConstructorParameter)
members.Add(new InjectionConstructor(item.Value));
else if (item is ConstructorParameter[])
members.AddRange((item as ConstructorParameter[]).Select(data => new InjectionConstructor(data.Value)));
});
var lifetimeManager = injectionMembers.OfType<LifetimeManager>().FirstOrDefault();
if (string.IsNullOrEmpty(name))
{
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType(type);
else if (lifetimeManager == null)
Current.RegisterType(type, members.ToArray());
else if (injectionMembers == null)
Current.RegisterType(type, lifetimeManager);
else
Current.RegisterType(type, lifetimeManager, members.ToArray());
}
else
{
if (lifetimeManager == null && injectionMembers == null)
Current.RegisterType(type, name);
else if (lifetimeManager == null)
Current.RegisterType(type, name, members.ToArray());
else if (injectionMembers == null)
Current.RegisterType(type, name, lifetimeManager);
else
Current.RegisterType(type, name, lifetimeManager, members.ToArray());
}
}
/// <summary>
/// 創建實例
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static object Resolve(Type source)
{
return Current.Resolve(source);
}
private static ConcurrentDictionary<string, Action<dynamic>> _handles = new ConcurrentDictionary<string, Action<dynamic>>();
/// <summary>
/// 當創建新實例時觸發
/// </summary>
/// <param name="handler"></param>
/// <returns></returns>
public void OnCreation<T>(Action<T> handler)
{
_handles.TryAdd(typeof(T).FullName, item => handler(item.Data));
}
public static bool HasRegistered(Type type)
{
return Current.IsRegistered(type);
}
/// <summary>
/// 創建泛型實例
/// </summary>
/// <returns></returns>
public static T Resolve<T>()
{
var result = Current.Resolve<T>();
Action<dynamic> handler;
if (_handles.TryGetValue(typeof(T).FullName, out handler))
{
handler(new EventArgs<T>(result));
}
return result;
}
/// <summary>
/// 創建泛型實例
/// </summary>
/// <returns></returns>
public static T Resolve<T>(string name)
{
return Current.Resolve<T>(name);
}
/// <summary>
/// 創建泛型實例集合
/// </summary>
/// <returns></returns>
public static T[] ResolveAll<T>()
{
var serviceImpls = Current.ResolveAll<T>();
List<T> proxiedServiceImpls = new List<T>();
foreach (var serviceImpl in serviceImpls)
{
Action<dynamic> handler;
if (_handles.TryGetValue(typeof(T).FullName, out handler))
{
handler(new EventArgs<T>(serviceImpl));
}
proxiedServiceImpls.Add(serviceImpl);
}
return proxiedServiceImpls.ToArray();
}
public static void Release(object obj)
{
Current.Teardown(obj);
}
}
}
輔助類
using System;
namespace Coralcode.Framework.Aspect
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class InjectAttribute : Attribute
{
/// <summary>
/// 注冊的名字
/// </summary>
public string Name { get; set; }
/// <summary>
/// 依賴注入的類型
/// </summary>
public Type RegisterType { get; set; }
/// <summary>
/// 注冊條件
/// </summary>
public RegisterCondition Condition { get; set; }
/// <summary>
/// aop類型
/// </summary>
public AopType AopType { get; set; }
/// <summary>
/// 生命周期類型
/// </summary>
public LifetimeManagerType LifetimeManagerType { get; set; }
}
[Flags]
public enum RegisterCondition
{
/// <summary>
/// 是否必須
/// </summary>
IsRequire = 1,
}
/// <summary>
/// 攔截類型
/// </summary>
public enum AopType
{
/// <summary>
/// 不攔截
/// </summary>
None,
/// <summary>
/// 虛方法攔截
/// </summary>
VirtualMethodInterceptor,
/// <summary>
/// 接口攔截
/// </summary>
InterfaceInterceptor,
/// <summary>
/// 動態代理攔截
/// </summary>
TransparentProxyInterceptor,
//這里可以添加自定義
}
public enum LifetimeManagerType
{
/// <summary>
/// 每次通過Resolve或ResolveAll調用對象的時候都會重新創建一個新的對象。
/// </summary>
Transient,
/// <summary>
/// 容器控制生命周期管理,這個生命周期管理器是RegisterInstance默認使用的生命周期管理器,也就是單件實例
/// </summary>
ContainerControlled,
/// <summary>
/// 分層生命周期管理器,這個管理器類似於ContainerControlledLifetimeManager,
/// 也是由UnityContainer來管理,也就是單件實例。
/// 不過與ContainerControlledLifetimeManager不 同的是,
/// 這個生命周期管理器是分層的,
/// 因為Unity的容器時可以嵌套的,所以這個生命周期管理器就是針對這種情況,
/// 當使用了這種生命周期管理器,
/// 父容器 和子容器所維護的對象的生命周期是由各自的容器來管理
/// </summary>
Hierarchica,
/// <summary>
/// 外部控制生命周期管理器,這個 生命周期管理允許你使用RegisterType和RegisterInstance來注冊對象之間的關系,
/// 但是其只會對對象保留一個弱引用,
/// 其生命周期 交由外部控制,也就是意味着你可以將這個對象緩存或者銷毀而不用在意UnityContainer,
/// 而當其他地方沒有強引用這個對象時,其會被GC給銷毀 掉。
/// </summary>
Externally,
/// <summary>
/// 每線程生命周期管理器,就是保證每個線程返回同一實例
/// </summary>
PerThread,
/// <summary>
/// 其類似於 TransientLifetimeManager,但是其不同在於,
/// 如果應用了這種生命周期管理器,
/// 則在第一調用的時候會創建一個新的對象,
/// 而再次通過 循環引用訪問到的時候就會返回先前創建的對象實例(單件實例),
/// </summary>
PerResolve,
}
}
Aop輔助類
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace Coralcode.Framework.Aspect.Unity
{
[AttributeUsage(AttributeTargets.Method|AttributeTargets.Class|AttributeTargets.Interface)]
public abstract class UnityAopAttribute : HandlerAttribute, ICallHandler, IInterceptionBehavior
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return this;
}
public System.Collections.Generic.IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
/// <summary>
/// 調用之后的實現邏輯
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
protected virtual void OnAfter(IMethodInvocation input)
{
}
/// <summary>
/// 調用之前的實現邏輯
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
protected virtual void OnBefore(IMethodInvocation input)
{
}
/// <summary>
/// 調用出現異常的實現邏輯
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
protected virtual void OnException(IMethodInvocation input, Exception ex)
{
throw ex;
}
/// <summary>
/// 接口注入時候的攔截方法
/// </summary>
/// <param name="input"></param>
/// <param name="nextMethod"></param>
/// <returns></returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate nextMethod)
{
OnBefore(input);
IMethodReturn result = null;
try
{
result = nextMethod()(input, nextMethod);
}
catch (Exception ex)
{
OnException(input, ex);
}
OnAfter(input);
return result;
}
/// <summary>
/// 虛方法注入的攔截方法
/// </summary>
/// <param name="input"></param>
/// <param name="nextMethod"></param>
/// <returns></returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate nextMethod)
{
OnBefore(input);
IMethodReturn result=null;
try
{
result = nextMethod()(input, nextMethod);
}
catch (Exception ex)
{
OnException(input, ex);
}
OnAfter(input);
return result;
}
public bool WillExecute
{
get { return true; }
}
}
}
得益於Mvc的filter,實際項目中很少用到AOP,如果需要使用繼承自這個類並標記在需要攔截的地方即可
EventBus
這里EventBus參考Abp和ApWorks的設計,這個發送的不算領域事件,是應用層
事件,在我項目中Event主要使用在三個地方
>* 統計模塊預定事件以后可以根據設計好的查詢需求去存放數據
這樣會比原來從原始表中load數據快很多.
>* 在比如菜單中可以注冊類型的事件實現菜單的動態修改。
這個會在做界面層的時候提到
>* 緩存數據的即時更新
