[译]Domain Events Pattern Example
本文展示的是一个关于网上调查的项目。想象下,当用户完成了一个调查,我们想通知所有人调查已经结束,分配一个人去检查调用问卷。
领域对象
public class Survey
{
public Guid Id { get; private set; }
public DateTime EndTime { get; private set; }
public string QualityChecker { get; set; }
public Survey()
{
this.Id = Guid.NewGuid();
}
public void EndSurvey()
{
EndTime = DateTime.Now;
DomainEvent.Raise(new EndOfSurvey() { Survey = this });
}
}
这个领域对象非常简单,只有一个行为:EndSurvey().
那么这里的DomainEvent
是个什么东西呢?它是一个静态类,它发布了一个EndOfSurvey
事件。从项目源码中可以看到所有的事件都放在名为Events的文件夹下面。领域对象放在Domain文件夹下面。
EndOfSurvey事件
现在Survey对象希望发布一个EndOfSurvey事件。这个事件的代码如下:
public class EndOfSurvey : IDomainEvent
{
public Survey Survey { get; set; }
}
EndOfSurvey
包含一个Survey
实例。它继承自IDomainEvent
,这样我们知道他是一个领域事件。本例中所有的事件都要继承自IDomainEvent
。
这个接口的定义很简单:
public interface IDomainEvent { }
DomainEvent类
public static class DomainEvent
{
public static IEventDispatcher Dispatcher { get; set; }
public static void Raise<T>(T @event) where T : IDomainEvent
{
Dispatcher.Dispatch(@event);
}
}
源码中的DomainEvent比这个要复杂点,但最重要的便是上面的代码了。
IEventDispatcher
是一个ioc容器。它负责找到正确的handler来处理EndOfSurvey
事件。
public interface IEventDispatcher
{
void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent;
}
泛型方法Raise<T>
能让我们发布无数的事件,Dispatcher
自动找出对应的handler。
下面定义一个处理所有事件的handler接口:
public interface IDomainHandler<T> where T : IDomainEvent
{
void Handle(T @event);
}
我将IEventDispatcher.cs和IDomainHandler.cs都放在一个名为Services的文件夹下面。其他的项目必须提供具体的实现。
domain程序集的代码就是这些了。
定义domain事件handler
我创建了另外一个项目用来写event handler。
EndOfSurveyHandler
用来处理EndOfSurvey
事件:
public class EndOfSurveyHandler:IDomainHandler<EndOfSurvey>
{
public void Handle(EndOfSurvey args)
{
args.Survey.QualityChecker = "Ivan Amalo";
// 发送邮件给Ivan,通知他来检查调查问卷
}
}
如果想使用repository进行一些数据持续化的工作,或者使用一些其他的服务,可以将这些repository和服务通过构造函数注入进来。
EndOfSurveyHandler
和EndOfSurvey
事件是怎么联系起来的呢?
将所有的代码集成起来
下面要讲Survey.FrontEnd是一个MVC + WebApi应用,这个应用将DomainEvent,Dispatcher,Handler都结合了起来。
这个项目依赖于Ninject.MVC3。
现在我们需要来实现在之前定义的IEventDispatcher。
public class NinjectEventContainer : IEventDispatcher
{
private readonly IKernel _kernel;
public NinjectEventContainer(IKernel kernel)
{
_kernel = kernel;
}
public void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent
{
foreach (var handler in _kernel.GetAll<IDomainHandler<TEvent>>())
{
handler.Handle(eventToDispatch);
}
}
}
Dispatch
方法使用kernel来查找所有实现了IDomainHandler
的handler。在我们的例子中查找的是EndOfSurveyHanlder
,然后执行它的Handle()
方法。
在NinjectWebCommon.cs中我们定义了handler和event的对应关系。
private static void RegisterServices(IKernel kernel)
{
DomainEvent.Dispatcher = new NinjectEventContainer(kernel);
kernel.Bind<IDomainHandler<EndOfSurvey>>().To<EndOfSurveyHandler>();
}
这就是我们将所有东西集成起来需要做的事情。
测试
我在EndOfSurveyHandler.cs中发布事件的代码那设置了一个断点,来测试事件已经发布,其对应的handler也被执行。
控制器的代码非常简单,如下:
public ActionResult Index()
{
var survey = new Core.Domain.Survey();
survey.EndSurvey();
return View(survey);
}
执行这个action, Ivan Amalo应该被分配成为这个调查问卷的检查者,并且将EndDate设为当前时间。
[译]Domain Events Pattern Example的更多相关文章
- ABP(现代ASP.NET样板开发框架)系列之14、ABP领域层——领域事件(Domain events)
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之14.ABP领域层——领域事件(Domain events) ABP是“ASP.NET Boilerplate P ...
- ABP领域层——领域事件(Domain events)
ABP领域层——领域事件(Domain events) 基于DDD的现代ASP.NET开发框架--ABP系列之14.ABP领域层——领域事件(Domain events) ABP是“ASP.NET B ...
- ABP的事件总线和领域事件(EventBus & Domain Events)
http://www.aspnetboilerplate.com/Pages/Documents/EventBus-Domain-Events EventBus EventBus是个单例,获得Even ...
- [译]C#7 Pattern Matching
原文 public struct Square { public double Side { get; } public Square(double side) { Side = side; } } ...
- 领域驱动设计(Domain Driven Design)参考架构详解
摘要 本文将介绍领域驱动设计(Domain Driven Design)的官方参考架构,该架构分成了Interfaces.Applications和Domain三层以及包含各类基础设施的Infrast ...
- [转载]领域驱动设计(Domain Driven Design)参考架构详解
摘要 本文将介绍领域驱动设计(Domain Driven Design)的官方参考架构,该架构分成了Interfaces.Applications和Domain三层以及包含各类基础设施的Infrast ...
- 领域驱动设计常见问题FAQ
本文出处:http://www.cqrs.nu/Faq What is a domain? The field for which a system is built. Airport managem ...
- CQRS FAQ (翻译)
我从接触ddd到学习cqrs有6年多了, 其中也遇到了不少疑问, 也向很多的前辈牛人请教得到了很多宝贵的意见和建议. 偶尔的机会看到国外有个站点专门罗列了ddd, cqrs和事件溯源的常见问题. 其中 ...
- A JavaFX based Game Authoring System
http://www.mirkosertic.de/doku.php/javastuff/javafxgameauthoring ——————————————————————————————————— ...
随机推荐
- POJ - 3984迷宫问题(最短路径输出)
题目链接:http://poj.org/problem?id=3984 题目: 迷宫问题 Time Limit: 1000MS Memory Limit: 65536K Total Submiss ...
- CentOS安装Python3.7
vscode设置python3.7调试环境:https://www.cnblogs.com/dotnetcrazy/p/9095793.html 先下载一下压缩包(FTP传也一样):weget htt ...
- ElasticSearch 2 (9) - 在ElasticSearch之下(图解搜索的故事)
ElasticSearch 2 (9) - 在ElasticSearch之下(图解搜索的故事) 摘要 先自上而下,后自底向上的介绍ElasticSearch的底层工作原理,试图回答以下问题: 为什么我 ...
- docker学习5--docker数据卷(volume)
https://blog.csdn.net/dream_broken/article/details/52314993 1.什么是数据卷volume 为了了解什么是Docker Volume,首先我们 ...
- P1024 一道naive的二分
好吧,这道题思路还是比较简单的.整个程序大体上很快就打出来了,然后修改了解为整数的情况. 但是交上去一直是50分,最后我很无耻的看了题解,然后抄了一个玄学if回来,瞬间AC,不知道为什么... 这句就 ...
- c#中委托和事件区别
委托和事件相同的功能 class Dem5 { public Action deHandler; public event Action eveHa; public Dem5() { deHandle ...
- POJ 3349 Snowflake Snow Snowflakes (Hash)
Snowflake Snow Snowflakes Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 48646 Accep ...
- decorator 装饰页面,根据不同设备自动切换移动和pc站
package com.thinkgem.jeesite.modules.sys.interceptor; import javax.servlet.http.HttpServletRequest; ...
- php递归函数中使用return的注意事项
php递归函数中使用return的时候会碰到无法正确返回想要的值得情况,如果不明白其中的原因,很难找出错误的,就下面的具体例子来说明一下吧: function test($i){ $i-=4; if( ...
- phpmyadmin拿webshell
思路:就是利用mysql的一个日志文件.这个日志文件每执行一个sql语句就会将其执行的保存.我们将这个日志文件重命名为我们的shell.php然后执行一条sql带一句话木马的命令.然后执行菜刀连接之! ...