使用MediatR完成基于内存级别的消息发布订阅

在微服务架构中领域驱动模型中处理领域事件的相关操作

在区分好领域模型后,就拿代码中来说嘛,用户领域中添加用户操作可能或存在跟用户相关的一些领域事件,在添加用户的时候会执行相关的领域事件

首先需要添加nuget包 MediatR

MediatR中有几个对象:IRequest,IRequestHandler,INotificationHandler

具体用法可以看下MediatR github

领域模型需要继承Entity,里面封装了 领域事件的相关操作

public abstract class Entity
{
int? _requestedHashCode;
int _Id;
public virtual int Id
{
get
{
return _Id;
}
protected set
{
_Id = value;
}
} private List<INotification> _domainEvents;
public IReadOnlyCollection<INotification> DomainEvents => _domainEvents?.AsReadOnly(); public void AddDomainEvent(INotification eventItem)
{
_domainEvents = _domainEvents ?? new List<INotification>();
_domainEvents.Add(eventItem);
} public void RemoveDomainEvent(INotification eventItem)
{
_domainEvents?.Remove(eventItem);
} public void ClearDomainEvents()
{
_domainEvents?.Clear();
} public bool IsTransient()
{
return this.Id == default(Int32);
} public override bool Equals(object obj)
{
if (obj == null || !(obj is Entity))
return false; if (Object.ReferenceEquals(this, obj))
return true; if (this.GetType() != obj.GetType())
return false; Entity item = (Entity)obj; if (item.IsTransient() || this.IsTransient())
return false;
else
return item.Id == this.Id;
} public override int GetHashCode()
{
if (!IsTransient())
{
if (!_requestedHashCode.HasValue)
_requestedHashCode = this.Id.GetHashCode() ^ ; return _requestedHashCode.Value;
}
else
return base.GetHashCode(); }
public static bool operator ==(Entity left, Entity right)
{
if (Object.Equals(left, null))
return (Object.Equals(right, null)) ? true : false;
else
return left.Equals(right);
} public static bool operator !=(Entity left, Entity right)
{
return !(left == right);
}
}

Entity

如:添加用户的时候添加一个默认角色相关的表处理

 public class TbUser : Entity, IAggregateRoot
{ public string UserName { get; set; }
public string UserPasswrod { get; set; }
public string UserPhone { get; set; }
public string XXXXX { get; set; }
[NotMapped]
public List<TbUserRole> TbUserRoles { get; set; }
public TbUser()
{
TbUserRoles = new List<TbUserRole>();
AddDomainEvent(new UserCreatedEvent() { tbUser = this });
} #region 领域职责 结合领域事件处理 黎又铭
/*
如:添加用户的时候添加默认角色 其实本身是可以直接在业务逻辑中写的
有点类是SQL触发器,添加用户的时候构建件默认角色信息模型触发事件添加角色信息 这里有注意到 实体模型并没有强制处理表接口的主外键关系 只是做了模型对象映射
*/
/// <summary>
/// 添加用户职责 只构建职责 不处理 处理交友领取事件的Command CommandHandler处理
/// </summary>
public void AddDefalutRole(TbUserRole tbUserRole)
{
TbUserRoles.Add(tbUserRole);
//添加默认角色的领域事件
AddDomainEvent(new UserRoleCreatedEvent() { TbUserRole = tbUserRole }); } #endregion }

User

先定义一个创建用户的命令操作: 这里的TbUser是领域时间模型,传递数据以及对领域模型事件操作

public class UserCreateCommand : IRequest<TbUser>
{ public TbUser tbUser{ get; set; }
}
public class UserCreateCommandHandler : IRequestHandler<UserCreateCommand, TbUser>
{ private IUserRepository _userRepository; public UserCreateCommandHandler(IUserRepository userRepository)
{
_userRepository = userRepository;
} public async Task<TbUser> Handle(UserCreateCommand request, CancellationToken cancellationToken)
{ await _userRepository.AddUserAsync(request.tbUser);
await _userRepository.UnitOfWork.SaveEntitiesAsync();
return request.tbUser;
}
}

这里还需要一个MediatR的扩展,发布领域事件

 static class MediatorExtension
{
/// <summary>
/// 异步处理领域事件
/// </summary>
/// <param name="mediator"></param>
/// <param name="ctx"></param>
/// <returns></returns>
public static async Task DispatchDomainEventsAsync(this IMediator mediator, UserDbContext ctx)
{
var domainEntities = ctx.ChangeTracker
.Entries<Entity>()
.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()); var domainEvents = domainEntities
.SelectMany(x => x.Entity.DomainEvents)
.ToList(); domainEntities.ToList()
.ForEach(entity => entity.Entity.ClearDomainEvents()); var tasks = domainEvents
.Select(async (domainEvent) => {
await mediator.Publish(domainEvent);
}); await Task.WhenAll(tasks);
}
}

扩展

下面是订阅领域事件

 public class UserRoleNotification : INotificationHandler<UserRoleCreatedEvent>
{
private IUserRepository _userRepository;
public UserRoleNotification(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task Handle(UserRoleCreatedEvent notification, CancellationToken cancellationToken)
{ await _userRepository.AddUserRoleAsync(notification.TbUserRole);
}

在controller中的使用:

[HttpPost]
[Route("adduser")]
public async Task<IActionResult> AddUser([FromBody] TbUser tbUser)
{
tbUser.AddDefalutRole(new TbUserRole { RoleId = , UserId = });
var command = new UserCreateCommand() { tbUser = tbUser };
var result = await _mediator.Send(command);
return Ok(result);
}

看下效果

MediatR 中介模式的更多相关文章

  1. [工作中的设计模式]中介模式模式Mediator

    一.模式解析 用一个中介者对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使耦合松散,而且可以独立地改变它们之间的交互. 中介模式又叫调停者模式,他有如下特点: 1.有多个系统或者对 ...

  2. 中介模式和学习日记Effective C++

    中介模式(Mediator):利用中介对象来封装一组对象交互.中保使对象并不需要显式地相互引用,使得松耦合,的交互. (1).中介者模式非常easy在系统中应用,也非常easy在系统中误用.当系统出现 ...

  3. Java设计模式(16)中介模式(Mediator模式)

    Mediator定义:用一个中介对象来封装一系列关于对象交互行为. 为何使用Mediator模式/中介模式 各个对象之间的交互操作非常多,每个对象的行为操作都依赖彼此对方,修改一个对象的行为,同时会涉 ...

  4. python 设计模式之中介模式

    Mediator Pattern:中介模式 中介模式提供了一系列统一的系统接口.此模式也被认为是行为模式,因为他能选择程序处理流程.  当许多类开始在交互中产生结果时,可以选用中介模式.当软件开始组织 ...

  5. .NET Core 使用MediatR CQRS模式

    前言 CQRS(Command Query Responsibility Segregation)命令查询职责分离模式,它主要从我们业务系统中进行分离出我们(Command 增.删.改)和(Query ...

  6. .NET Core 使用MediatR CQRS模式 读写分离

    前言 CQRS(Command Query Responsibility Segregation)命令查询职责分离模式,它主要从我们业务系统中进行分离出我们(Command 增.删.改)和(Query ...

  7. <人人都懂设计模式>-中介模式

    真正的用房屋中介来作例子, 好的书籍总是让人记忆深刻. class HouseInfo: def __init__(self, area, price, has_window, has_bathroo ...

  8. Github上优秀的.NET Core项目

    Github上优秀的.NET Core开源项目的集合.内容包括:库.工具.框架.模板引擎.身份认证.数据库.ORM框架.图片处理.文本处理.机器学习.日志.代码分析.教程等. Github地址:htt ...

  9. 【转载】Github上优秀的.NET Core项目

    Github上优秀的.NET Core项目 Github上优秀的.NET Core开源项目的集合.内容包括:库.工具.框架.模板引擎.身份认证.数据库.ORM框架.图片处理.文本处理.机器学习.日志. ...

随机推荐

  1. MT【183】借力打力

    (2011安徽省赛)设$f(x)=ax^3+bx+c(a,b,c\in R)$,当$0\le x \le1$时,$0\le f(x)\le1$,求$b$的可能的最大值. 分析:$f(0)=c,f(1) ...

  2. 【BZOJ1024】[SCOI2009]生日快乐(搜索)

    [BZOJ1024][SCOI2009]生日快乐(搜索) 题面 BZOJ 洛谷 题解 看到这个数据范围就感觉是爆搜.我们爆搜左右分成多少块,这样子左右的面积已知,再枚举一下横着切还是竖着切,这样子就可 ...

  3. Burpsuit分块传输插件绕WAF原理和技巧(转)

      0x00 原理 给服务器发送payload数据包,使得waf无法识别出payload,当apache,tomcat等web容器能正常解析其内容.如图一所示 0x02  实验环境 本机win10+x ...

  4. 解题:CF1063F String Journey

    题面 分析性质以进行DP 性质1:一定有一个最优解通过每次删除第一个或最后一个字符达到 这个脑补一下就能证明了 那么我们设$dp[i]$表示后缀$[i,n]$选出一个前缀所能达到的最大长度,从右往左D ...

  5. fzyzojP3979 -- [校内训练20180914]魔法方阵

    原题见CF632F https://blog.csdn.net/Steaunk/article/details/80217764 这个比较神仙了 点边转化, 把max硬生生转化成了路径最大值,再考虑所 ...

  6. 【洛谷P1126】机器人搬重物

    题目大意:给定一个 N 行,M 列的地图,一个直径为 1.6 的圆形机器人需要从起点走到终点,每秒钟可以实现:向左转,向右转,向前 1-3 步.求从起点到终点最少要多长时间. 题解:相比于普通的走迷宫 ...

  7. Go(02)windows环境搭建和vscode配置

    之前讲述过linux环境下Go语言开发环境搭建,这次简述下windows的搭建以及vscode配置 windows环境搭建 同样去https://studygolang.com/dl下载windows ...

  8. 基于docker的spark-hadoop分布式集群之一: 环境搭建

    一.软件准备 1.基础docker镜像:ubuntu,目前最新的版本是18 2.需准备的环境软件包: (1) spark-2.3.0-bin-hadoop2.7.tgz (2) hadoop-2.7. ...

  9. Kafka 0.8 Consumer设计解析

    摘要 本文主要介绍了Kafka High Level Consumer,Consumer Group,Consumer Rebalance,Low Level Consumer实现的语义,以及适用场景 ...

  10. JAVA-Servlet高级应用

    会话只是指一段指定的时间间隔. 会话跟踪是维护用户状态(数据)的一种方式.它也被称为servlet中的会话管理. Http协议是一个无状态的,所以我们需要使用会话跟踪技术来维护用户状态. 每次用户请求 ...