Lind.DDD.Events领域事件介绍

时间:2023-01-08 18:40:18

回到目录

闲话多说

领域事件大叔感觉是最不好讲的一篇文章,所以拖欠了很久,但最终还是在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 = ,
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);
}
}
}
}

感谢各位的阅读!

回到目录

Lind.DDD.Events领域事件介绍的更多相关文章

  1. Lind&period;DDD敏捷领域驱动框架~介绍

    回到占占推荐博客索引 最近觉得自己的框架过于复杂,在实现开发使用中有些不爽,自己的朋友们也经常和我说,框架太麻烦了,要引用的类库太多:之前架构之所以这样设计,完全出于对职责分离和代码附复用的考虑,主要 ...

  2. Lind&period;DDD敏捷领域驱动框架~Lind&period;DDD各层介绍

    回到目录 Lind.DDD项目主要面向敏捷,快速开发,领域驱动等,对于它的分层也是能合并的合并,比之前大叔的框架分层更粗糙一些,或者说更大胆一些,在开发人员使用上,可能会感觉更方便了,更益使用了,这就 ...

  3. Lind&period;DDD&period;Events事件总线~自动化注册

    回到目录 让大叔兴奋的自动化注册 对于领域事件之前说过,在程序启动时订阅(注册)一些事件处理程序,然后在程序的具体位置去发布(触发)它,这是传统的pub/sub模式的体现,当然也没有什么问题,为了让它 ...

  4. Lind&period;DDD&period;Repositories&period;EF层介绍

    回到目录 Lind.DDD.Repositories.EF以下简称Repositories.EF,之所以把它从Lind.DDD中拿出来,完全出于可插拔的考虑,让大家都能休会到IoC的魅力,用到哪种方法 ...

  5. Lind&period;DDD&period;Repositories&period;Redis层介绍

    回到目录 之前已经发生了 大叔之前介绍过关于redis的文章,有缓存,队列,分布式pub/sub,数据集缓存以及仓储redis的实现等等,而今天在Lind.DDD的持久化组件里,redis当然也有一席 ...

  6. Lind&period;DDD&period;Paging分页模块介绍

    回到目录 分页组件网上有很多,MVC.Pager,JSPager等,通过实现方式大体分为前端分页和后端分页,前端分页是前台对list内存本地集合进行分页,缺点就是在大数据情况下,内存占用过高:后端分页 ...

  7. Lind&period;DDD&period;Repositories&period;Mongo层介绍

    回到目录 之前已经发生了 大叔之前讲过被仓储化了的Mongodb,而在大叔开发了Lind.DDD之后,决定把这个东西再搬到本框架的仓储层来,这也是大势所趋的,毕竟mongodb是最像关系数据库的NoS ...

  8. Lind&period;DDD&period;Authorization用户授权介绍

    回到目录 Lind.DDD.Authorization是Lind.DDD框架的组成部分,之所以把它封装到框架里,原因就是它的通用性,几乎在任何一个系统中,都少不了用户授权功能,用户授权对于任何一个系统 ...

  9. ABP入门系列(19)——使用领域事件

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1.引言 最近刚学习了下DDD中领域事件的理论知识,总的来说领域事件主要有两个作用,一是解耦,二是 ...

随机推荐

  1. ACM&sol;ICPC 之 数据结构-邻接表&plus;BFS&lpar;TSH OJ-无线广播Broadcast&rpar;

    这道题中若能够构成互不干扰的区域,其构成的图其实就是汉密尔顿路(Hamilton road),因此如果能够观察出来可以直接转化为汉密尔顿路的存在性证明,即便不能观察,我相信ACMer也能转化为BFS问 ...

  2. &lbrack;Cocos2d-x For WP8&rsqb;Scene场景

         场景(CCScene) 在游戏里,场景就是关卡. CCScene是app工作流程上独立块,一个app可能拥有多个scene,但是在任何时候只能有一个是激活状态的.一个CCScene对象由一个 ...

  3. readonly disabled 区别

    readonly 提交表单时包含该属性的内容 控件 disabled 不包含该属性

  4. eclipse 常用快捷键整理

    1.整理代码的快捷键ctrl+shift + F 2.跳转代码行ctrl+L 3.可以列出所有快捷键  Ctrl+Shift+L

  5. 这年头做开源项目,被冷嘲热讽,FreeSql 0&period;0&period;4

    FreeSql 项目大概在20天前想着要做的,今天发布0.0.4在群里被一位大神讽刺. 这位无名氏哥们的观点,先声明这不是找安慰的文章,更加不是报复打击的目的. 1 所以这个比EF好在哪里 2 毕竟E ...

  6. python笔记1——关于文件的打开与读写

    一.文件的打开与关闭1.open,close函数 #-*- coding:utf-8 -*- # 1.w 写模式,它是不能读的,如果用w模式打开一个已经存在的文件,会清空以前的文件内容,重新写 # w ...

  7. 动态调用WebService&lpar;传对象返回接受对象&rpar;

    基础属性//客户端代理服务命名空间,可以设置成需要的值. string ns = string.Format("WindowsForms"); private Assembly a ...

  8. 一个能够编写、运行SQL查询并可视化结果的Web应用:SqlPad

    SqlPad 是一个能够用于编写.运行 SQL 查询并可视化结果的 Web 应用.支持 PostgreSQL.MySQL 和 SQL Server.SqlPad 目前仅适合单个团队在内网中使用,它直接 ...

  9. Google官方教程之Selling In-app Products

    1.原文链接[需FQ]:http://developer.android.com/training/in-app-billing/index.html 2.平时对于英文文档都是大概读一下,现在翻译文章 ...

  10. &lbrack;转载&rsqb;win10&lpar;64bit&rpar;上安装MySQL-python

    https://blog.csdn.net/builder_taoge/article/details/78292302 https://blog.csdn.net/qq_26808915/artic ...