CRUD全栈式编程架构之服务层的设计
Posted Skyven
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CRUD全栈式编程架构之服务层的设计相关的知识,希望对你有一定的参考价值。
服务层代码
首先我先放出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) {
if (search == null) return base.GetFilter(null);
var expression = (Expression<Func<PrivateLesson, bool>>)(item => true); 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数据快很多.
>* 在比如菜单中可以注册类型的事件实现菜单的动态修改。
这个会在做界面层的时候提到
>* 缓存数据的即使更新
以上是关于CRUD全栈式编程架构之服务层的设计的主要内容,如果未能解决你的问题,请参考以下文章
全栈式部署:SpringCloud 微服务+Docker + Vue + nginx 前后端一站式部署