MediatR是一款基于中介者模式的思想
而实现的.NET库,支持.NET Framework和跨平台 的.NET Core。主要是为了解决进程内消息发送与消息处理过程之间的耦合问题。MediatR的作者是Jimmy Bogard,如果你不知道这个人,想必你也用过他开发的AutoMapper吧。
它通过一种进程内消息传递机制(无其他外部依赖),进行请求/响应、命令、查询、通知和事件的消息传递,并通过泛型来支持消息的智能调度。
MediatR有两种消息处理模式:
在现实生活中,中介者的存在是不可缺少的,比如房屋中介、招聘平台等;网络世界中有很多中介者模式的身影,例如QQ游戏平台,聊天室、QQ群和短信平台。
在软件设计领域,为什么要使用中介者模式呢?如果不使用中介者模式的话,各个同事对象将会相互进行引用,如果每个对象都与多个对象进行交互时,将会形成如下图所示的网状结构。
从上图可以发现,如果不使用中介者模式的话,每个对象之间过度耦合,这样的既不利于类的复用也不利于扩展。如果引入了中介者模式,那么对象之间的关系将变成星型结构,采用中介者模式之后会形成如下图所示的结构:
中介者模式使之前的网状结构,现在变成了以中介者为中心的星星结构。这样的设计大大减少了系统的耦合度。
中介者就像一个容器的,它自己把控着整个流程,和每一个对象都有或多或少,或近或远的联系,多个对象之间不用理睬其他对象发生了什么,只是负责自己的模块就好,然后把消息发给中介者,让中介者再分发给其他的具体对象,从而实现通讯 —— 这个思想就是中介者的核心思想,而且也是DDD领域驱动设计的核心思想之一。
中介者模式是23种设计模式的其中一个。中介者模式是一个行为设计模式,它允许我们公开一个统一的接口,系统的 不同部分 可以通过该接口进行 通信,而 不需要 显式的相互作用; 类图结构如下:
中介者使各个对象不需要显式地相互引用,从而使其耦合性降低,而且可以独立地改变它们之间的交互。
以下情况下可考虑使用中介者模式:
以下是一个具体例子,联合国就是一个中介者:
以下是 MediatR 的一些适用场景:
总体而言,MediatR适用于需要解耦请求和处理逻辑的场景,能够提高代码的可读性、可维护性和可扩展性。它可以与其他架构模式(如CQRS、事件驱动架构等)结合使用,以满足不同的业务需求和系统设计要求。
开发环境:
平台版本是:.NET6
开发框架:ASP.NET Core WebApi
开发工具:Visual Studio 2022
此案例,演示一个游戏管理模块的“添加游戏”这个功能。
//引用命名空间
using MediatR;
namespace MediatRWebApp.Requests
{
//Request类,string是处理者响应的数据类型
public class AddGameRequest : IRequest<string>
{
public int GameId { get; set; }
public string GameName { get; set; }
public string GameType { get; set; }
}
}
using MediatR;
using MediatRWebApp.Requests;
namespace MediatRWebApp.RequestHandlers
{
//Handler类型,PingRequest是其处理的请求类型,string是处理者响应的数据类型
public class AddGameRequestHandler : IRequestHandler<AddGameRequest, string>
{
/// <summary>
/// 处理AddGameRequest请求,返回string类型的响应
/// </summary>
/// <param name="request">请求对象</param>
/// <param name="cancellationToken">取消令牌</param>
/// <returns></returns>
public Task<string> Handle(AddGameRequest request, CancellationToken cancellationToken)
{
//做如下的一些处理:(代码略)
//验证输入的参数是否正确
//可能还要做名称的唯一性判断
//根据Request来创建一个实体对象
//用仓储把他保存到数据库中
return Task.FromResult("添加游戏成功!");
}
}
}
步骤三:在服务容器中注册AddGameRequestHandler
using MediatR;
using MediatRWebApp.RequestHandlers;
//在Program.cs 注册AddGameRequestHandler
builder.Services.AddMediatR(typeof(AddGameRequestHandler ));
步骤四:在控制器方法中用Mediator的Send方法发送请求,对应的Request请求将由注册过的Handler来处理。
//在控制器中使用
using MediatR;
using MediatRWebApp.Requests;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace MediatRWebApp.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class GameController : ControllerBase
{
//构造函数注入Mediator
private readonly IMediator _mediator;
//构造方法
public GameController(IMediator mediator)
{
_mediator = mediator;
}
/// <summary>
/// 添加游戏的接口方法
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> Add([FromBody]AddGameDto input)
{
AddGameRequest request = new AddGameRequest (){
GameName = input.GameName,
GameType = input.GameType
};
var response = await _mediator.Send(request);
return Ok(response);
}
}
}
using MediatR;
public class DomainNotification: INotification
{
public DomainNotification(string message)
{
Message = message;
}
public string Message { get; set; } //通知的消息
}
//步骤二:创建一个消息处理器
public class DomainNotificationHandler : INotificationHandler<DomainNotification>
{
/// <summary>
/// 处理消息
/// </summary>
/// <param name="notification"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task Handle(DomainNotification notification, CancellationToken cancellationToken)
{
Console.WriteLine("{0} 被消息处理器DomainNotificationHandler处理了!!", notification.Message);
return Task.CompletedTask;
}
}
//步骤二:创建另一个消息处理器
public class AnotherNotificationHandler : INotificationHandler<DomainNotification>
{
/// <summary>
/// 处理消息
/// </summary>
/// <param name="notification"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public Task Handle(DomainNotification notification, CancellationToken cancellationToken)
{
Console.WriteLine("{0} 被消息处理器AnotherNotificationHandler处理了!!", notification.Message);
return Task.CompletedTask;
}
}
using MediatR;
using MediatRWebApp.Notifications;
using MediatRWebApp.Requests;
[Route("api/[controller]")]
[ApiController]
public class PingController : ControllerBase
{
private readonly IMediator _mediator;
//构造方法
public PingController (IMediator mediator)
{
_mediator = mediator;
}
/// <summary>
/// 测试方法
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> TestNotification()
{
//发送请求消息 PingRequest
var response = await _mediator.Send(new PingRequest());
//将通知消息广播出去,订阅了DomainNotification的Handler都能够响应
await _mediator.Publish(new DomainNotification("添加成功"));
return Ok(response);
}
}
本文到此结束,欢迎各位的支持和鼓励,如果对你有帮助的话,请点赞+关注,或者转发给需要的朋友。