Skip to content

Commit

Permalink
Event Bus & DomainNotification
Browse files Browse the repository at this point in the history
  • Loading branch information
v-anzha committed Dec 4, 2018
1 parent 79a5809 commit c4c406d
Show file tree
Hide file tree
Showing 15 changed files with 305 additions and 28 deletions.
12 changes: 11 additions & 1 deletion Christ3D.Domain.Core/Bus/IMediatorHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
using Christ3D.Domain.Core.Commands;

using Christ3D.Domain.Core.Events;

namespace Christ3D.Domain.Core.Bus
{
Expand All @@ -18,5 +18,15 @@ public interface IMediatorHandler
/// <param name="command"> 命令模型,比如RegisterStudentCommand </param>
/// <returns></returns>
Task SendCommand<T>(T command) where T : Command;


/// <summary>
/// 引发事件,通过总线,发布事件
/// </summary>
/// <typeparam name="T"> 泛型 继承 Event:INotification</typeparam>
/// <param name="event"> 事件模型,比如StudentRegisteredEvent,</param>
/// 请注意一个细节:这个命名方法和Command不一样,一个是RegisterStudentCommand注册学生命令之前,一个是StudentRegisteredEvent学生被注册事件之后
/// <returns></returns>
Task RaiseEvent<T>(T @event) where T : Event;
}
}
4 changes: 0 additions & 4 deletions Christ3D.Domain.Core/Christ3D.Domain.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Folder Include="Events\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="FluentValidation" Version="8.1.0-preview1" />
<PackageReference Include="MediatR" Version="5.1.0" />
Expand Down
21 changes: 21 additions & 0 deletions Christ3D.Domain.Core/Events/Event.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using MediatR;

namespace Christ3D.Domain.Core.Events
{
/// <summary>
/// 事件模型 抽象基类,继承 INotification
/// 也就是说,拥有中介者模式中的 发布/订阅模式
/// </summary>
public abstract class Event : INotification
{
// 时间戳
public DateTime Timestamp { get; private set; }

// 每一个事件都是有状态的
protected Event()
{
Timestamp = DateTime.Now;
}
}
}
30 changes: 30 additions & 0 deletions Christ3D.Domain.Core/Notifications/DomainNotification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using Christ3D.Domain.Core.Events;

namespace Christ3D.Domain.Core.Notifications
{
/// <summary>
/// 领域通知模型,用来获取当前总线中出现的通知信息
/// 继承自领域事件和 INotification(也就意味着可以拥有中介的发布/订阅模式)
/// </summary>
public class DomainNotification : Event
{
// 标识
public Guid DomainNotificationId { get; private set; }
// 键(可以根据这个key,获取当前key下的全部通知信息)
// 这个我们在事件源和事件回溯的时候会用到,伏笔
public string Key { get; private set; }
// 值(与key对应)
public string Value { get; private set; }
// 版本信息
public int Version { get; private set; }

public DomainNotification(string key, string value)
{
DomainNotificationId = Guid.NewGuid();
Version = 1;
Key = key;
Value = value;
}
}
}
49 changes: 49 additions & 0 deletions Christ3D.Domain.Core/Notifications/DomainNotificationHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediatR;

namespace Christ3D.Domain.Core.Notifications
{
/// <summary>
/// 领域通知处理程序,把所有的通知信息放到事件总线中
/// 继承 INotificationHandler<T>
/// </summary>
public class DomainNotificationHandler : INotificationHandler<DomainNotification>
{
// 通知信息列表
private List<DomainNotification> _notifications;

// 每次访问该处理程序的时候,实例化一个空集合
public DomainNotificationHandler()
{
_notifications = new List<DomainNotification>();
}

// 处理方法,把全部的通知信息,添加到内存里
public Task Handle(DomainNotification message, CancellationToken cancellationToken)
{
_notifications.Add(message);
return Task.CompletedTask;
}

// 获取当前生命周期内的全部通知信息
public virtual List<DomainNotification> GetNotifications()
{
return _notifications;
}

// 判断在当前总线对象周期中,是否存在通知信息
public virtual bool HasNotifications()
{
return GetNotifications().Any();
}

// 手动回收(清空通知)
public void Dispose()
{
_notifications = new List<DomainNotification>();
}
}
}
12 changes: 9 additions & 3 deletions Christ3D.Domain/CommandHandlers/CommandHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Christ3D.Domain.Core.Bus;
using Christ3D.Domain.Core.Commands;
using Christ3D.Domain.Core.Notifications;
using Christ3D.Domain.Interfaces;
using Microsoft.Extensions.Caching.Memory;
using System;
Expand Down Expand Up @@ -33,20 +34,25 @@ public CommandHandler(IUnitOfWork uow, IMediatorHandler bus, IMemoryCache cache)
_cache = cache;
}


//将领域命令中的验证错误信息收集
//目前用的是缓存方法(以后通过领域通知替换)
protected void NotifyValidationErrors(Command message)
{
List<string> errorInfo = new List<string>();
foreach (var error in message.ValidationResult.Errors)
{
errorInfo.Add(error.ErrorMessage);
//errorInfo.Add(error.ErrorMessage);

//将错误信息提交到事件总线,派发出去
_bus.RaiseEvent(new DomainNotification("", error.ErrorMessage));
}
//将错误信息收集
_cache.Set("ErrorData", errorInfo);

//将错误信息收集一:缓存方法(错误示范)
//_cache.Set("ErrorData", errorInfo);
}


//工作单元提交
//如果有错误,下一步会在这里添加领域通知
public bool Commit()
Expand Down
20 changes: 15 additions & 5 deletions Christ3D.Domain/CommandHandlers/StudentCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Threading.Tasks;
using Christ3D.Domain.Commands;
using Christ3D.Domain.Core.Bus;
using Christ3D.Domain.Core.Notifications;
using Christ3D.Domain.Events;
using Christ3D.Domain.Interfaces;
using Christ3D.Domain.Models;
using MediatR;
Expand Down Expand Up @@ -63,14 +65,17 @@ public Task<Unit> Handle(RegisterStudentCommand message, CancellationToken cance
// 实例化领域模型,这里才真正的用到了领域模型
// 注意这里是通过构造函数方法实现
var customer = new Student(Guid.NewGuid(), message.Name, message.Email, message.Phone, message.BirthDate);

// 判断邮箱是否存在
// 这些业务逻辑,当然要在领域层中(领域命令处理程序中)进行处理
if (_studentRepository.GetByEmail(customer.Email) != null)
{
//这里对错误信息进行发布,目前采用缓存形式
List<string> errorInfo = new List<string>() { "The customer e-mail has already been taken." };
Cache.Set("ErrorData", errorInfo);
////这里对错误信息进行发布,目前采用缓存形式
//List<string> errorInfo = new List<string>() { "该邮箱已经被使用!" };
//Cache.Set("ErrorData", errorInfo);

//引发错误事件
Bus.RaiseEvent(new DomainNotification("", "该邮箱已经被使用!"));
return Task.FromResult(new Unit());
}

Expand All @@ -83,7 +88,7 @@ public Task<Unit> Handle(RegisterStudentCommand message, CancellationToken cance
// 提交成功后,这里需要发布领域事件
// 比如欢迎用户注册邮件呀,短信呀等

// waiting....
Bus.RaiseEvent(new StudentRegisteredEvent(customer.Id, customer.Name, customer.Email, customer.BirthDate, customer.Phone));
}

return Task.FromResult(new Unit());
Expand All @@ -95,6 +100,7 @@ public Task<Unit> Handle(UpdateStudentCommand message, CancellationToken cancell
{
if (!message.IsValid())
{
NotifyValidationErrors(message);
return Task.FromResult(new Unit());

}
Expand All @@ -107,6 +113,7 @@ public Task<Unit> Handle(UpdateStudentCommand message, CancellationToken cancell
if (!existingCustomer.Equals(customer))
{

Bus.RaiseEvent(new DomainNotification("", "该邮箱已经被使用!"));
return Task.FromResult(new Unit());

}
Expand All @@ -117,6 +124,7 @@ public Task<Unit> Handle(UpdateStudentCommand message, CancellationToken cancell
if (Commit())
{

Bus.RaiseEvent(new StudentUpdatedEvent(customer.Id, customer.Name, customer.Email, customer.BirthDate, customer.Phone));
}

return Task.FromResult(new Unit());
Expand All @@ -128,6 +136,7 @@ public Task<Unit> Handle(RemoveStudentCommand message, CancellationToken cancell
{
if (!message.IsValid())
{
NotifyValidationErrors(message);
return Task.FromResult(new Unit());

}
Expand All @@ -136,6 +145,7 @@ public Task<Unit> Handle(RemoveStudentCommand message, CancellationToken cancell

if (Commit())
{
Bus.RaiseEvent(new StudentRemovedEvent(message.Id));
}

return Task.FromResult(new Unit());
Expand Down
37 changes: 37 additions & 0 deletions Christ3D.Domain/EventHandlers/StudentEventHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Threading;
using System.Threading.Tasks;
using Christ3D.Domain.Events;
using MediatR;

namespace Christ3D.Domain.EventHandlers
{
public class StudentEventHandler :
INotificationHandler<StudentRegisteredEvent>,
INotificationHandler<StudentUpdatedEvent>,
INotificationHandler<StudentRemovedEvent>
{
// 学习被注册成功后的事件处理方法
public Task Handle(StudentRegisteredEvent message, CancellationToken cancellationToken)
{
// 恭喜您,注册成功,欢迎加入我们。

return Task.CompletedTask;
}

// 学生被修改成功后的事件处理方法
public Task Handle(StudentUpdatedEvent message, CancellationToken cancellationToken)
{
// 恭喜您,更新成功,请牢记修改后的信息。

return Task.CompletedTask;
}

// 学习被删除后的事件处理方法
public Task Handle(StudentRemovedEvent message, CancellationToken cancellationToken)
{
// 您已经删除成功啦,记得以后常来看看。

return Task.CompletedTask;
}
}
}
26 changes: 26 additions & 0 deletions Christ3D.Domain/Events/Student/StudentRegisteredEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Christ3D.Domain.Core.Events;

namespace Christ3D.Domain.Events
{
public class StudentRegisteredEvent : Event
{
public StudentRegisteredEvent(Guid id, string name, string email, DateTime birthDate, string phone)
{
Id = id;
Name = name;
Email = email;
BirthDate = birthDate;
Phone = phone;
}
public Guid Id { get; set; }

public string Name { get; private set; }

public string Email { get; private set; }

public DateTime BirthDate { get; private set; }

public string Phone { get; private set; }
}
}
15 changes: 15 additions & 0 deletions Christ3D.Domain/Events/Student/StudentRemovedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using Christ3D.Domain.Core.Events;

namespace Christ3D.Domain.Events
{
public class StudentRemovedEvent : Event
{
public StudentRemovedEvent(Guid id)
{
Id = id;
}

public Guid Id { get; set; }
}
}
26 changes: 26 additions & 0 deletions Christ3D.Domain/Events/Student/StudentUpdatedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Christ3D.Domain.Core.Events;

namespace Christ3D.Domain.Events
{
public class StudentUpdatedEvent : Event
{
public StudentUpdatedEvent(Guid id, string name, string email, DateTime birthDate,string phone)
{
Id = id;
Name = name;
Email = email;
BirthDate = birthDate;
Phone = phone;
}
public Guid Id { get; set; }

public string Name { get; private set; }

public string Email { get; private set; }

public DateTime BirthDate { get; private set; }

public string Phone { get; private set; }
}
}
Loading

0 comments on commit c4c406d

Please sign in to comment.