• Lind.DDD.Events领域事件介绍


    回到目录

    闲话多说

    领域事件大叔感觉是最不好讲的一篇文章,所以拖欠了很久,但最终还是在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<int, decimal, RechargeXuexibaDTO> 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<OrderPaid>(new OrderUpdateEventHandler());
            }
    
            public System.Guid Id { get; set; }
            public System.Guid UserId { get; set; }
            public string UserName { get; set; }
            public decimal TotalFee { get; set; }
    
            /// <summary>
            /// 用户提交并确认订单
            /// </summary>
            public void ComfirmOrder()
            {
                //事件发布
                Lind.DDD.Events.EventBus.Instance.Publish(new OrderConfirm
                {
                    TotalFee = TotalFee,
                    UserName = UserName,
                    UserId = UserId,
                });
            }
    
        }
    
        #endregion

    下面是领域事件源

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

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

       /// <summary>
        /// 订单被插入时的处理程序
        /// </summary>
        public class OrderInsertEventHandler :
              Lind.DDD.Events.IEventHandler<Events.OrderConfirm>
        {
            #region IEventHandler<OrderSigned> 成员
    
            public void Handle(Events.OrderConfirm evt)
            {
                //处理訂單确认的逻辑
                var orderRepository = new Lind.DDD.Repositories.EF.EFRepository<Orders>();
                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的处理程序就是一个异步的。

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

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

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

         /// <summary>
            /// 全局统一注册所有事件处理程序,实现了IEventHandlers的
            /// </summary>
            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);
                        }
                    }
                }
            }

    感谢各位的阅读!

    回到目录

  • 相关阅读:
    Android进阶——Volley+Https给你的安卓应用加上SSL证书(转)
    VSFTP上传不了
    mysql主从同步配置
    EditText插入表情(字符串)到光标所在位置
    js实现监听页面滚动实现图片延迟加载
    android开发技巧——仿新版QQ锁屏下弹窗(转)
    [原创]JAVA技巧:去除ArrayList<Object>里面的重复记录
    [原创]JAVA号码工具类:实现手机固话号码判断与区号截取
    [原创]FreeSWITCH实现多人来电思路
    [原创]Linux实现服务延迟启动
  • 原文地址:https://www.cnblogs.com/lori/p/5168935.html
Copyright © 2020-2023  润新知