MEDIATR 一个低调的中介者类库

微软官方的开源项目eShopOnContainers中,用到了一个实现中介者模式的类库:MediatR。这个类库的作者叫Jimmy Bogard,在其gtihub主页上可以看到,注明的对象映射组件AutoMapper 就是他写的。其博客上的自我介绍是这么写的:

Headspring的首席架构师,《MVC in Action》的作者,国际演说家,高产的开源软件开发者。擅长分布式系统,REST,消息,领域驱动设计和CQRS。

回到MediatR这个组件,他是一个低调的类库,致力于解决一个简单的问题:解耦进程内消息的发送与处理。跨平台,支持.NET4.5和netstandard1.1。

中介者模式

在继续研究MediatR之前,先回顾下“中介者设计模式(Mediator)”,中介者模式的定义为:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互应用,从而使其耦合松散,而且可以独立地改变他们之间的交互。其结构图如下:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

以下是一个具体的中介者模式demo:

/// <summary>
/// 抽象中介者
/// </summary>
public abstract class AbstractMediator
{public abstract void SendMessage(string msg, AbstractColleague colleague);
}/// <summary>
/// 抽象同事类
/// </summary>
public abstract class AbstractColleague
{public string Name { get; set; }protected AbstractMediator Mediator;protected AbstractColleague(AbstractMediator mediator){Mediator = mediator;}public abstract void PrintMsg(string msg);
}/// <summary>
/// 具体中介者,负责同事类之间的交互,他必须清楚的知道需要交互的所有同事类的细节。
/// </summary>
public class Mediator : AbstractMediator
{public AbstractColleague ColleagueA;public AbstractColleague ColleagueB;public override void SendMessage(string msg, AbstractColleague colleague){if (colleague == ColleagueA){ColleagueB.PrintMsg(msg);}else if (colleague == ColleagueB){ColleagueA.PrintMsg(msg);}}
}/// <summary>
/// 具体同事类A,他是不知道其他具体同事类的存在的。他与其他同事类的交互,是通过中介者来实现的。
/// </summary>
public class ConcreteColleagueA : AbstractColleague
{public ConcreteColleagueA(AbstractMediator mediator) : base(mediator){}public void SendMessage(string msg){Mediator.SendMessage(msg,this);}public override void PrintMsg(string msg){Console.WriteLine($"A收到消息:{msg}");}
}public class ConcreteColleagueB : AbstractColleague
{public ConcreteColleagueB(AbstractMediator mediator) : base(mediator){}public void SendMessage(string msg){Mediator.SendMessage(msg, this);}public override void PrintMsg(string msg){Console.WriteLine($"B收到消息:{msg}");}
}class Program
{/// <summary>/// 客户端调用/// </summary>/// <param name="args"></param>static void Main(string[] args){var mediator = new Mediator();var colleagueA = new ConcreteColleagueA(mediator);var colleagueB = new ConcreteColleagueB(mediator);mediator.ColleagueA = colleagueA;mediator.ColleagueB = colleagueB;colleagueA.SendMessage("你好B,中午一起饭吧?");colleagueB.SendMessage("你好A,好的。");Console.ReadLine();}
}

程序输出如下:

B收到消息:你好B,中午一起饭吧?
A收到消息:你好A,好的。

中介者类把不同的同事类之间的交互提升到其内部,这样同事类之间的交互变得简单了,同事类不需要知道其他同事类的存在,通过中介者类来完成与其他同事类的交互。另一方面,中介者类本身复杂性增加,中介者类需要知道所有的同事类,例如调用他们的公共方法。

MediatR

MediatR可以与很多依赖注入组件一起工作,其github文档有详细说明。以下是我结合Autofac组件的代码研究。

新建ASP.NET Core Console程序,添加MediatR和Autofac依赖包。然后配置Autofac:

var builder = new ContainerBuilder();
// mediator itself
builder.RegisterType<Mediator>().As<IMediator>().InstancePerLifetimeScope();// request handlers
builder.Register<SingleInstanceFactory>(ctx => {var c = ctx.Resolve<IComponentContext>();return t => c.TryResolve(t, out var o) ? o : null;}).InstancePerLifetimeScope();// notification handlers
builder.Register<MultiInstanceFactory>(ctx => {var c = ctx.Resolve<IComponentContext>();return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));}).InstancePerLifetimeScope();//builder.RegisterType<PingHandler>().AsImplementedInterfaces().InstancePerDependency();
builder.RegisterAssemblyTypes(typeof(Program).GetTypeInfo().Assembly).AsImplementedInterfaces();var mediator = builder.Build().Resolve<IMediator>();
Test(mediator);

MediatR可以支持几种模式,有请求/响应模式,发布模式。

请求/响应模式,也可以叫做命令模式,主要适用于命令和查询场景。一个请求只能被一个处理者捕获,如果存在多个处理者,那么只有最后一个处理者会被激活。

以下代码声明消息,然后定义处理者:

/*注意:请求/响应接口适用于命令和查询场景。*都只能有一个Handler,如果注册多个,只有最后一个会生效。*/
public class Ping : IRequest<string>
{public int MsgId { get; set; }
}public class PingHandler : IRequestHandler<Ping, string>
{public Task<string> Handle(Ping request, CancellationToken cancellationToken){return Task.FromResult($"MsgID={request.MsgId},Pong");}
}/// <summary>
/// 为了方便,不需要CancellationToken的Handler,可以继承AsyncRequestHandler类
/// </summary>
public class AsyncNoCancellation : AsyncRequestHandler<Ping, string>
{protected override Task<string> HandleCore(Ping request){return Task.FromResult("Pong");}
}/// <summary>
/// 如果Handler是完全同步的,可以继承RequestHandler类
/// </summary>
public class SyncHandler : RequestHandler<Ping, string>
{protected override string HandleCore(Ping request){return $"SyncHandler Pong";}
}

然后就是发送请求了:

var response = await mediator.Send(new Ping(){MsgId = 100});
Console.WriteLine(response); // "SyncHandler Pong"

另外,请求/响应模式还支持不带任何返回值的处理者:

public class OneWay:IRequest
{public int MsgId { get; set; }
}public class OneWayHandler : IRequestHandler<OneWay>
{public Task Handle(OneWay request, CancellationToken cancellationToken){Console.WriteLine($"{request.MsgId},OneWayHandler");return Task.CompletedTask;}
}

发布模式,一般用于发布一个事件,通知订阅者某件事情已经发生,对此事感兴趣的订阅者可以采取行动了。一般是一个发布这,多个订阅者。

public class Hello : INotification
{public int MsgId { get; set; }
}public class Hello1 : INotificationHandler<Hello>
{public async Task Handle(Hello notification, CancellationToken cancellationToken){await Task.Delay(3000);Console.WriteLine($"{notification.MsgId},{Thread.CurrentThread.ManagedThreadId}");}
}public class Hello2 : INotificationHandler<Hello>
{public async Task Handle(Hello notification, CancellationToken cancellationToken){await Task.Delay(3000);Console.WriteLine($"{notification.MsgId},{Thread.CurrentThread.ManagedThreadId}");}
}

像这样发布消息:

  1. await mediator.Publish(new Hello() {MsgId = 300});

程序输出如下:

300,4
300,5
Main 5

这里可以看到,2个订阅者都被激活了。另外,可以看到不同的订阅者所处的线程ID不一样,他们是异步执行的。

原文地址 :http://coderyu.com/2018/04/02/mediatr-%E4%B8%AD%E4%BB%8B%E8%80%85/

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321556.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ApacheSkyWalking APM 生态衍生多语言监控, 支持 .NET Core

Apache SkyWalking .NET core 探针发布&#xff01;GitHub: https://github.com/apache/incubator-skywalking 码云Gitee: https://gitee.com/OpenSkywalking/sky-walkingApache SkyWalking在4月初&#xff0c;发布了加入Apache孵化器后的第一个版本&#xff1a;5.0.0-alpha。…

使用TFS CI/CD 完成 VSTS 插件自动化部署和发布

Visual Studio Team Service 经过了13年的版本演进和5年的在线运营&#xff0c;现在已经是最成熟的商用DevOps工具链&#xff0c;Marketplace作为VSTS为全球开发者提供各种类型的插件市场&#xff0c;为Visual Studio, Visual Studio Code和Visual Studio Team Service本身提供…

用C# (.NET Core) 实现迭代器设计模式

本文的概念来自深入浅出设计模式一书项目需求有两个饭店合并了, 它们各自有自己的菜单. 饭店合并之后要保留这两份菜单.这两个菜单是这样的:菜单项MenuItem的代码是这样的:最初我们是这样设计的, 这是第一份菜单:这是第2份菜单:同时有两个菜单存在的问题问题就是多个菜单把事情…

2020-09-18

1.处理调用子组件方法时&#xff0c;报错undefined问题 2.var 、const 、let区别 3. curl -X GET --header "Accept: */*" "访问地址" 4.mysql中的日期格式化 5. ant-design-vue-jeecg

.NET Core/.NET之Stream简介

之前写了一篇C#装饰模式的文章用.NET Core实现装饰模式和.NET Core的Stream简介 提到了.NET Core的Stream, 所以这里尽量把Stream介绍全点. (都是书上的内容).NET Core/.NET的Streams首先需要知道, System.IO命名空间是低级I/O功能的大本营.Stream的结构.NET Core里面的Stream主…

I - Trade Gym - 100212I 网络流

网络流好题 给出A、B两个点集&#xff0c;A、B之间有边相连&#xff0c;而A和B的内部均无边相连。 题目要求求出最多删除A、B之间的多少边&#xff0c;才能使得A中点的度数至少都为2&#xff0c;B中点的度数也至少都为2。 先求出每个点的度数&#xff0c;从每个点v出发&…

【深搜】骑士游历(ssl 1277)

骑士游历 Description 如下图所示有m*n(n,m<15)一个棋盘&#xff0c;在棋盘左下角的A&#xff08;1,1&#xff09;点&#xff0c;有一个中国象棋〈马〉&#xff0c;并约定马走的规则&#xff1a; ①走日字&#xff1b;②只能向右走。 Sample Input &#xff19; &…

修复迁移后Net Standard项目中的错误

接上一章&#xff0c;项目编译结果如下&#xff1a;解决依赖dll引用在Net Framework项目的引用如下&#xff1a;各引用和作用&#xff1a;log4net(1.10.0.0) 用于写框架日志Castle.DynamicProxy(1.1.5.1) 用于代理类生成Micosoft.Practice.EnterpiseLibrary 微软企业库&#xf…

迁移Net项目为Net Core\Standard项目

背景&#xff1a;我们公司内部有自己ORM开发框架&#xff0c;最新因为需要将系统迁移到国产服务器上&#xff0c;所以首先需要将最基础的ORM框架改造可以运行在国产服务器上。对于我们Net来说&#xff0c;优选Net Core。在迁移的过程中&#xff0c;将一些经验和坑记录下来&…

迁移后的Net Standard版本的类库测试和多平台项目实测

按照第一步的方法&#xff0c;添加一个Net Core的MSTest项目&#xff0c;然后将原来的测试项目下的代码迁移到新测试 项目中&#xff0c;然后引用新的Beyondbit.Framework Core类库。然后运行单元测试项目和集成测试项目即可。测试当中单元测试下项目没有问题&#xff0c;一遍就…

.Net Core小技巧 - 使用Swagger上传文件

前言随着前后端分离开发模式的普及&#xff0c;后端人员更多是编写服务端API接口。调用接口实现文件上传是一个常见的功能&#xff0c;同时也需要一个选择文件上传的界面&#xff0c;可以编写前端界面上传&#xff0c;可以使用Postman、curl来模拟上传请求。上述的方式多多少少…

容器化分布式日志组件ExceptionLess的Angular前端UI

写在前面随着微服务架构的流行&#xff0c;日志也需要由专门的分布式日志组件来完成这个工作&#xff0c;我们项目使用的是 ExceptionLess 这个组件&#xff0c;它是前后端分离的&#xff1b;这篇文章我们就来实践容器化 ExceptionLess 的前端&#xff0c;并为其包含一个 nginx…

EF 6.x、EF Core实现dynamic动态查询和EF Core实现多个上下文实例池你了解多少?

前言很长一段时间没有写博客了&#xff0c;今天补上一篇吧&#xff0c;偶尔发现不太愿意写博客了&#xff0c;太耗费时间&#xff0c;不过还是在坚持当中&#xff0c;毕竟或许写出来的东西能帮到一些童鞋吧&#xff0c;接下来我们直奔主题。无论是在在EF 6.x还是EF Core中对于原…

1、play编程基础

1、Action、Controller、Result Action指的是动作&#xff0c;play中大多数请求可以使用action来处理&#xff0c;一个请求对应一个动作也就是一个java方法&#xff0c;然后处理请求返回一个响应&#xff0c;这个响应用Result来体现 Controller就是一个继承了 play.mvc.Contro…

【动态规划】城市交通

城市交通 Description 有n个城市&#xff0c;编号1~n&#xff0c;有些城市之间有路相连&#xff0c;有些则没有&#xff0c;有路则当然有一个距离。现在规定只能从编号小的城市到编号大的城市&#xff0c;问你从编号为1的城市到编号为n的城市之间的最短距离是多少&#xff1f…

AspNetCoreApi 跨域处理(CORS )

如果咱们有处理过MV5 跨域问题这个问题也不大。&#xff08;1&#xff09;为什么会出现跨域问题&#xff1a;浏览器安全限制了前端脚本跨站点的访问资源&#xff0c;所以在调用WebApi 接口时不能成功访问资源&#xff0c;原因“同源策略”的存在&#xff1a;同源指以下几点相同…

业务配置开发平台qMISPlat 2.0 产品介绍

qMISPlat是什么qMISPlat(业务配置开发平台)是一套基于.net core 2.0、跨平台的&#xff0c;面向开发人员和具有一定技术水平的业务人员使用的业务配置开发平台。基于此平台您只需通过配置和少量开发即可快速搭建满足用户需求的业务系统&#xff0c;大大降低项目开发工作量。平台…

2、异步HTTP编程

1、处理异步结果 在内部&#xff0c;play框架是自下而上异步的。Play以异步、非阻塞方式处理每个请求。应用程序代码应尽量避免阻塞控制器&#xff0c;这种阻塞操作的常见例子有JDBC调用、流式API、HTTP请求和长计算。因此应尽量通过保持控制器异步的方法使得应用进行扩展&…

3、play中的模板引擎

1、模板格式 Play默认的模板引擎是一种基于scala的安全模板引擎&#xff0c;尽管模板引擎使用Scala作为表达式语言&#xff0c;但是非常简单易学。参数类型使用后缀语法指定&#xff08;例如&#xff1a; id&#xff1a;Long&#xff09;&#xff0c;泛型类型是使用[]符号&…

.NET Core调用WCF的最佳实践

现在.NET Core貌似很火&#xff0c;与其他.NET开发者交流不说上几句.NET Core都感觉自己落伍了一样。但是冷静背后我们要也看到.NET Core目前还有太多不足&#xff0c;别的不多说&#xff0c;与自家的服务框架WCF集成起来就不咋地&#xff0c;从最初不支持&#xff0c;到现在有…