初学者浅度剖析eShopOnContainers 里面用到的MediatR .
一.介绍
简单了解下开源项目 MedatR, eShopOnContainers, MediatR作者Jimmy Bogard :
Simple mediator implementation in .NET
In-process messaging with no dependencies.
Supports request/response, commands, queries, notifications and events, synchronous and async with intelligent dispatching via C# generic variance.
.NET中的简单中介实现 进程内没有依赖关系消息传递。支持以同步或异步的形式进行请求/响应,命令,查询,通知和事件的消息传递,并通过C#泛型支持消息的智能调度。
MediatR实现Pipeline ,通过Autofac 注入Log,FluentValidation ,来实现管道里记录日志,管道里验证实体数据.
二.MediatR的使用
1.安装NuGet包:
Install-Package MediatR.Extensions.Microsoft.DependencyInjectionFixed
Install-Package Autofac.Extensions.DependencyInjection
2.修改Startup.cs文件
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var container = new ContainerBuilder();
container.Populate(services);
container.RegisterModule(new MediatorModule());
return new AutofacServiceProvider(container.Build());
}
3.添加MediatorModule.cs文件
添加 builder.RegisterGeneric(typeof(xxx<,>)).As(typeof(IPipelineBehavior<,>)); 按你添加的顺序执行管道
public class MediatorModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)
.AsImplementedInterfaces(); // Register all the Command classes (they implement IRequestHandler) in assembly holding the Commands
builder.RegisterAssemblyTypes(typeof(CreateOrderCommand).GetTypeInfo().Assembly)
.AsClosedTypesOf(typeof(IRequestHandler<,>));
// Register the DomainEventHandler classes (they implement INotificationHandler<>) in assembly holding the Domain Events
// builder.RegisterAssemblyTypes(typeof(ValuesController.Pings).GetTypeInfo().Assembly)
// .AsClosedTypesOf(typeof(INotificationHandler<>)); // Register the Command's Validators (Validators based on FluentValidation library)
builder
.RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly)
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
.AsImplementedInterfaces(); builder.Register<ServiceFactory>(context =>
{
var componentContext = context.Resolve<IComponentContext>();
return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; };
}); builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
// builder.RegisterGeneric(typeof(TransactionBehaviour<,>)).As(typeof(IPipelineBehavior<,>)); }
}
4.添加LoggingBehavior.cs文件
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger) => _logger = logger; public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
_logger.LogInformation("----- Handling command {CommandName} ({@Command})", request.GetGenericTypeName(), request);
var response = await next();
_logger.LogInformation("----- Command {CommandName} handled - response: {@Response}", request.GetGenericTypeName(), response); return response;
}
}
5.添加ValidatorBehavior.cs文件
public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger<ValidatorBehavior<TRequest, TResponse>> _logger;
private readonly IValidator<TRequest>[] _validators; public ValidatorBehavior(IValidator<TRequest>[] validators, ILogger<ValidatorBehavior<TRequest, TResponse>> logger)
{
_validators = validators;
_logger = logger;
} public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var typeName = request.GetGenericTypeName(); _logger.LogInformation("----- Validating command {CommandType}", typeName); var failures = _validators
.Select(v => v.Validate(request))
.SelectMany(result => result.Errors)
.Where(error => error != null)
.ToList(); if (failures.Any())
{
_logger.LogWarning("Validation errors - {CommandType} - Command: {@Command} - Errors: {@ValidationErrors}", typeName, request, failures); throw new OrderingDomainException(
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
} return await next();
}
}
6.添加CreateOrderCommandValidator.cs
public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
{
public CreateOrderCommandValidator()
{
RuleFor(command => command.City).NotEmpty();
RuleFor(command => command.Street).NotEmpty();
RuleFor(command => command.State).NotEmpty();
RuleFor(command => command.Country).NotEmpty();
RuleFor(command => command.ZipCode).NotEmpty();
RuleFor(command => command.CardNumber).NotEmpty().Length(, );
RuleFor(command => command.CardHolderName).NotEmpty();
RuleFor(command => command.CardExpiration).NotEmpty().Must(BeValidExpirationDate).WithMessage("Please specify a valid card expiration date");
RuleFor(command => command.CardSecurityNumber).NotEmpty().Length();
RuleFor(command => command.CardTypeId).NotEmpty();
RuleFor(command => command.OrderItems).Must(ContainOrderItems).WithMessage("No order items found");
} private bool BeValidExpirationDate(DateTime dateTime)
{
return dateTime >= DateTime.UtcNow;
} private bool ContainOrderItems(IEnumerable<CreateOrderCommand.OrderItemDTO> orderItems)
{
return orderItems.Any();
}
}
初学者浅度剖析eShopOnContainers 里面用到的MediatR .的更多相关文章
- 初学者应该怎么学习前端?web前端的发展路线大剖析!
写在最前: 优秀的Web前端开发工程师要在知识体系上既要有广度和深度!应该具备快速学习能力. 前端开发工程师不仅要掌握基本的Web前端开发技术,网站性能优化.SEO和服务器端的基础知识,而且要学会运用 ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- [.NET领域驱动设计实战系列]专题十:DDD扩展内容:全面剖析CQRS模式实现
一.引言 前面介绍的所有专题都是基于经典的领域驱动实现的,然而,领域驱动除了经典的实现外,还可以基于CQRS模式来进行实现.本专题将全面剖析如何基于CQRS模式(Command Query Respo ...
- SpringMVC源码剖析(一)- 从抽象和接口说起
SpringMVC作为Struts2之后异军突起的一个表现层框架,正越来越流行,相信javaee的开发者们就算没使用过SpringMVC,也应该对其略有耳闻.我试图通过对SpringMVC的设计思想和 ...
- Unity协程(Coroutine)原理深入剖析
Unity协程(Coroutine)原理深入剖析 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 其实协程并没有那么复杂,网上很多地方都说是多 ...
- Node初学者入门,一本全面的NodeJS教程(转载)
分类 JS学习 发布 ourjs 2013-12-02 注意 转载须保留原文链接,译文链接,作者译者等信息. 作者: Manuel Kiessling 翻译: goddyzhao &a ...
- Unity协程(Coroutine)原理深入剖析(转载)
记得去年6月份刚开始实习的时候,当时要我写网络层的结构,用到了协程,当时有点懵,完全不知道Unity协程的执行机制是怎么样的,只是知道函数的返回值是IEnumerator类型,函数中使用yield r ...
- .NET平台技术体系梳理+初学者学习路径推荐+我们的愿景与目标
文章出自:http://www.cnblogs.com/ice-river/p/3475041.html 一 .NET平台技术体系梳理 .NET平台应用领域众多(桌面开发,web开发,移动开发),不断 ...
- Spring 事务管理高级应用难点剖析--转
第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...
随机推荐
- 转贴:C语言链表基本操作
http://www.oschina.net/code/snippet_252667_27314#comments 这个代码有很多错误,估计是从老谭书上抄来但是很多还抄错了:对照老谭的书好好研究下.切 ...
- gamit安装
需要准备的文件: 默认已安装好虚拟机和Ubuntu系统 1.输入用户名密码,进入Ubuntu10.04桌面.按下“Ctrl+Alt+T”,进入终端: 2.在终端输入“sudo gedit /etc/a ...
- mysql5.7.22的安装与配置(适用mysql5.7.20至mysql5.7.22版本)
一.解压Mysql5.7.20安装包,刚解压是没有 data 这个文件夹的 二.配置mysql环境变量,创建MYSQL_HOME,然后在Path上添加%MYSQL_HOME%\bin; 三.配置m ...
- 【记录】有趣的python模块记录
1. paramiko: 基于SSH用于连接远程服务器并执行相关操作,公钥私钥登录等等
- php中static静态变量的使用方法详解
php中的变量作用范围的另一个重要特性就是静态变量(static 变量).静态变量仅在局部函数域中存在且只被初始化一次,当程序执行离开此作用域时,其值不会消失,会使用上次执行的结果. 看看下面 ...
- CVE-2017-8046 复现与分析
环境搭建 使用的项目为https://github.com/spring-guides/gs-accessing-data-rest.git里面的complete,直接用IDEA导入,并修改pom.x ...
- virtualbox+vagrant学习-2(command cli)-18-vagrant ssh-config命令
SSH Config 格式: vagrant ssh-config [options] [name|id] 这将从SSH直接将SSH配置文件的有效配置输出到正在运行的vagrant 计算机(而不是使用 ...
- Spring源码分析(十三)缓存中获取单例bean
摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 介绍过FactoryBean的用法后,我们就可以了解bean加载的过程了 ...
- Carthage 的使用
第一步,当然是安装 Carthage,网上找吧 第二步,找到你要用的那个仓库,eg:https://github.com/jiutianhuanpei/SHBPlayer 第三步,cd 到工程根目录下 ...
- http协议中的keeplive是做什么的?它的适应场景是什么?
1.Http底层也是通过TCP传输的. 2.HTTP keep-alive Http是一个”请求-响应”协议,它的keep-alive主要是为了让多个http请求共享一个Tcp连接,以避免每个Http ...