博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lind.DDD.Events领域事件介绍
阅读量:6046 次
发布时间:2019-06-20

本文共 5281 字,大约阅读时间需要 17 分钟。

闲话多说

领域事件大叔感觉是最不好讲的一篇文章,所以拖欠了很久,但最终还是在2015年年前(阴历)把这个知识点讲一下,事件这个东西早在C#1.0时代就有了,那时学起来也是一个费劲,什么是委托,哪个是事件,搞的大家是糊里糊涂,进入C#2.0时代后,大叔也买了一本书,对于delegate和event这两个知识点看了至少有20几遍,感觉稍微有点明白了,明白了其中的真谛和用意。

委托:方法的规范,方法的模板,可以代表一类方法的集合

事件:委托的实例,事件在使用之前需要为它赋值,当然赋的就是一个方法;事件可以注册和取消,当你注册一个事件之后,在事件被触发后,被注册的方法将会被执行,这一般被称为“方法的回调”,在设计模式里,又被称为“pub/sub模式”,即发布/订阅模式;在C#语言发展过程中,设计得为程序开发者考虑的很多,有些写法得到了精简,如Action和Func委托的出现之后,我们基本上告别了delegate,这对程序开发人员无疑是一件好事。

大叔框架中的事件

在大叔框架里,事件是常客,比如在早期的仓储代码里,你可以传递一个Action<string>的委托,来进行日志的记录,这种方法在IoC出现后,被大叔屏蔽了,原因不在这里说了,还有就是在N层架构里,WEB层与BLL层进行通讯时,WEB层通过HttpClient请求第三方的API获取数据,而BLL层的方法需要用到这个第三方API的返回值,而在BLL层直接访问HTTP显然是不合适的,所以,在WEB层到BLL层的方法参数设计时,需要有一个委托来接改从WEB层回调的方法返回值,这种代码一般称为“方法回调”。

web层向BLL层传入一个委托

var entity = rechargeService.RechargeAuto(                        task,                        beforeTime,                        out result,                        (studentid, money) =>                        {              //代码              });

 

BLL层接改这个委托的返回值,代码在调用bll层这个方法时,首先会回调web层的http的方法

public Task_xuexiba_Recharge RechargeAuto(         Task_Info task,         DateTime beforeTime,         out bool result,         Func
api) {      //代码    }
var apiEntity = api(task.Task_ParametersForXuexibaRecharge.StudentID, task.Task_ParametersForXuexibaRecharge.Money);

Lind.DDD框架里的领域事件

事件源后缀:Event

事件处理方法后缀:EventHandler

领域事件一般出现个领域实体里,在实体被建立时,会订阅和自己有关的事件,每个事件都有一个或者多个事件处理方法,事件处理方法可以进行数据库操作,或者网络和文件的操作,如发通知,写文件等,所以有时候我们的事件需要设计成异步的事件。

程序中的事件事件

  #region 领域模型    public class Order    {        public Order()        {            Lind.DDD.Events.EventBus.Instance.Subscribe(new OrderInsertEventHandler());            Lind.DDD.Events.EventBus.Instance.Subscribe
(new OrderUpdateEventHandler()); } public System.Guid Id { get; set; } public System.Guid UserId { get; set; } public string UserName { get; set; } public decimal TotalFee { get; set; } ///
/// 用户提交并确认订单 /// public void ComfirmOrder() { //事件发布 Lind.DDD.Events.EventBus.Instance.Publish(new OrderConfirm { TotalFee = TotalFee, UserName = UserName, UserId = UserId, }); } } #endregion

下面是领域事件源

///     /// 订单被确认的事件源    ///     public class OrderConfirm : Lind.DDD.Events.IEvent    {        public override string ToString()        {            return "订单已经确认";        }        ///         /// 订单总金额        ///         public decimal TotalFee { get; set; }        ///         /// 购买者ID        ///         public Guid UserId { get; set; }        ///         /// 购买者        ///         public string UserName { get; set; }        #region IEvent 成员        public Guid AggregateRoot        {            get { throw new NotImplementedException(); }        }        #endregion    }

下面是领域事件的处理程序

  ///     /// 订单被插入时的处理程序    ///     public class OrderInsertEventHandler :          Lind.DDD.Events.IEventHandler
{ #region IEventHandler
成员 public void Handle(Events.OrderConfirm evt) { //处理訂單确认的逻辑 var orderRepository = new Lind.DDD.Repositories.EF.EFRepository
(); orderRepository.SetDataContext(new testEntities()); orderRepository.Insert(new Orders { Id = Guid.NewGuid(), OrderStatus = 1, TotalFee = evt.TotalFee, UserId = evt.UserId, UserName = evt.UserName, }); } #endregion }

如果希望将自己的事件处理程序设计成异常的,即不阻塞当前线程的,可以让它添加HandlesAsynchronouslyAttribute这个特性,如下面这个发送Email的处理程序就是一个异步的。

  ///     /// 发邮件功能[某个事件的行为]    ///     [HandlesAsynchronouslyAttribute]    public class SendEmailEventHandler :        IEventHandler
, IEventHandler
{ #region IEventHandler
成员 public void Handle(OrderEvent evt) { Console.WriteLine("生成和确认订单{0}时发Email", evt.OrderId); } #endregion #region IEventHandler
成员 public void Handle(UserEvent evt) { Console.WriteLine("建立用户后发Email,用户ID{0}", evt.UserId); } #endregion }

 全局注册所有事件处理程序

这个是看完ABP之后的想法,原理是把BIN下所有继承了IEventHandler的类都自动注册到事件总线中,然后在事件被触发后,就自动执行你订阅的方法了,在项目开发过程中,推荐使用这种方法,但需要注意的是,你的事件处理程序必须是显示定义的,不能使用匿名的处理程序.

   ///         /// 全局统一注册所有事件处理程序,实现了IEventHandlers的        ///         public void SubscribeAll()        {            var types = AppDomain.CurrentDomain.GetAssemblies()                   .SelectMany(a => a.GetTypes()                   .Where(t => t.GetInterfaces().Contains(typeof(IEventHandlers))))                   .Where(i => !Excepts.Contains(i.Name))                   .ToArray();            foreach (var item in types)            {                if (!item.ContainsGenericParameters)                {                    var en = Activator.CreateInstance(item);                    foreach (var t in item.GetInterfaces().Where(i => i.Name != "IEventHandlers"))                    {                        Subscribe(t, en);                    }                }            }        }

 

感谢各位的阅读!

转载于:https://www.cnblogs.com/lori/p/5168935.html

你可能感兴趣的文章
HTMLHelper
查看>>
快速构建Windows 8风格应用29-捕获图片与视频
查看>>
OC语言Block和协议
查看>>
使用xpath时出现noDefClass的错误(找不到某个类)
查看>>
.Net规则引擎介绍 - REngine
查看>>
CSS3 transforms 3D翻开
查看>>
利用传入的Type类型来调用范型方法的解决方案
查看>>
Top命令内存占用剖析
查看>>
转 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO
查看>>
求带分数(蓝桥杯)
查看>>
Retrofit 入门学习
查看>>
Spring Boot学习笔记
查看>>
laravel 集合接口
查看>>
java.exe进程来源排查录
查看>>
C++实现KMP模式匹配算法
查看>>
JSONObject与JSONArray的使用
查看>>
除了《一无所有》,我一无所有
查看>>
每日英语:China Seeks to Calm Anxiety Over Rice
查看>>
C++中struct和class的区别 [转]
查看>>
C++ ofstream和ifstream详细用法
查看>>