使用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. ANSI C 常见宏的使用

    1. __VA_ARGS__: ...  表示可变参数列表,__VA_ARGS__在预处理中会被可变参数列表替代 2. __FILE__:正在编译文件的文件路径 3. __LINE__:正在编译文件的 ...

  2. Gym - 101522H Hit!

    H. Hit! time limit per test 1.0 s memory limit per test 256 MB input standard input output standard ...

  3. 【刷题】LOJ 6010 「网络流 24 题」数字梯形

    题目描述 给定一个由 \(n\) 行数字组成的数字梯形如下图所示.梯形的第一行有 \(m\) 个数字.从梯形的顶部的 \(m\) 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至 ...

  4. POJ 1797 Heavy Transportation / SCU 1819 Heavy Transportation (图论,最短路径)

    POJ 1797 Heavy Transportation / SCU 1819 Heavy Transportation (图论,最短路径) Description Background Hugo ...

  5. java web 验证码-字符变形(推荐)

    该文章转载自:http://www.cnblogs.com/jianlun/articles/5553452.html 因为在我做的这个系统中发现验证码有点偏上,整体效果看起来不太好,就做了一些修改. ...

  6. string::replace

    #include <string> #include <cctype> #include <algorithm> #include <iostream> ...

  7. Java基础-SSM之mybatis的统计函数和分页查询

    Java基础-SSM之mybatis的统计函数和分页查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

  8. starUML的使用方法和各种线条的含义

    使用方法https://www.cnblogs.com/syncCN/p/5433746.html 各种线条的含义:https://www.cnblogs.com/huaxingtianxia/p/6 ...

  9. 读asyncio模块源码时的知识补漏

    硬着头皮看了一周的asyncio模块代码,了解了大概的执行流程,引用太多,成尤其是对象间函数的引用. 光是这么一段简单的代码: # coding: utf8 import asyncio import ...

  10. D. Dasha and Chess(交互题)

    题目链接:http://codeforces.com/contest/1100/problem/D 题目大意:给你一个999*999的图,然后有666个黑色旗子,一个白色棋子,每一次白色棋子只能在它附 ...