CRUD全棧式編程架構之服務層的設計

服務層代碼

首先我先放出2個主要類的代碼再分別講解面試

接口sql

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只是一個泛型限制裏面暫時沒有任何實現express

 

如下是一個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只是一個泛型限制,裏面暫時沒有任何實現app

 

泛型維度的縮放


對於上面排序和查詢的功能並非必定都須要,因此作了維度縮放,能夠從三種
維度去使用Crud的服務.
對於服務的實現上加入了模型實體(也就是和數據庫映射的模型),這麼作的好處是
使用接口的人無需知道數據庫怎麼存放表怎麼映射,接口和實現分離。框架

Mapper

咱們選用EmitMapper做爲Entity和DTO的映射,目前來看這個性能是除了直接賦值
以外性能最好的了,網上有不少對比文章請自行參考。固然若是你不習慣也能夠
換一種實現ide

這裏代碼參考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數據快不少.>*  在好比菜單中能夠註冊類型的事件實現菜單的動態修改。    這個會在作界面層的時候提到>*  緩存數據的即時更新

相關文章
相關標籤/搜索