根据MediatR的Contract Messages自动生成Minimal WebApi接口

大家好,我是失业在家,正在找工作的博主Jerry。今天给大家介绍一个能大大减少ASP.Net Minimal WebApi编码量的方法。

我们一般会把微服务的VO和DTO封装成消息类,并作为WebApi的Request和Response参数进行网络传递。

如果使用MediatR,我们封装的消息类就要实现 MediatR Contract 接口 IRequest<> 或者INotification,  例如我的代码如下:

namespace MediatRApplication.CategoryCRUD

{public class CreateCategory : IRequest<CreateCategoryResult>{public string Message { get; set; }}public class CreateCategoryResult{public string Message { get; set; }}public class ReadCategory : IRequest<ReadCategoryResult>{public string Message { get; set; }}public class ReadCategoryResult{public string Message { get; set; }}public class UpdateCategory : IRequest<UpdateCategoryResult>{public string Message { get; set; }}public class UpdateCategoryResult{public string Message { get; set; }}public class DeleteCategory : IRequest{public string Message { get; set; }}
}

如上代码是对Category业务实体进行CRUD操作封装的DTO消息类,每个消息类都实现了MediatR的IRequest接口。有了消息类,就可以对每个消息类编写处理器(Handler),以实现业务功能。

有了消息类,就需要为每个消息类创建WebApi接口,以实现消息的Request和Response。WebAPI接口中没有业务逻辑,只需要调用MediatR的Send方法将消息类发送给Handler即可。

但是,由于消息类比较多,一个一个创建WebApi接口是一件费时费力,并且容易出错的事情。作为一个架构师,是无法忍受程序员们干这些出力不讨好的事情的。

所以,为了项目,为了大家的Work Life Banlance, 我把创建WebApi这件事情减少成了一行代码。是的,你没看错,就是只要一行代码:

app.MapMediatorWebAPIs(typeof(CreateCategory).Assembly);

只要在ASP.Net Minimal API 项目的Progam文件中加入这一行代码,就可以把指定程序集中所有实现了IRequest<>和INotification的消息类自动生成WebAPI接口。

5d7c93173b0e897a0ef61e373e226890.png

看起来很神奇,其实也不神奇。主要就是两个字:反射。还有泛型。

简单来说,就是在指定程序集中,通过反射查找那些类实现了IRequest<>或者INotification,然后在通过对泛型映射WebAPI方法的反射调用,为每个消息类生成WebApi接口。

Let me show you the code:

using MediatR;

using MediatRApplication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Reflection;
using System.Xml.Linq;namespace MediatRWebAPI
{public static class MediatorWebAPIExtensions{/// <summary>/// 扩展方法,为所有MediatR Contract 消息类创建WebAPI接口/// </summary>/// <param name="app"></param>/// <param name="assemblies">Contract 消息类所在程序集</param>/// <returns></returns>public static IEndpointRouteBuilder MapMediatorWebAPIs(this IEndpointRouteBuilder app, params Assembly[] assemblies){//为所有实现了IRequest<>的消息类创建WebAPI接口Type genericRequestType = typeof(IRequest<>);var sendMethodInfo = typeof(MediatorWebAPIExtensions).GetMethod("MapMediatorSendApi", BindingFlags.NonPublic | BindingFlags.Static);foreach (var assembly in assemblies){//获取该程序集中所有实现了IRequest<>的消息类类型var requestTypes = assembly.GetTypes().Where(type => !type.IsInterface && type.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == genericRequestType));foreach (var requestType in requestTypes){//获取IRequest<>中尖括号中的泛型参数类型。var responseType = requestType.GetInterfaces().First(t => t.IsGenericType && t.GetGenericTypeDefinition() == genericRequestType).GetGenericArguments().First();//反射调用泛型映射WebApi方法var genericMethod = sendMethodInfo.MakeGenericMethod(requestType, responseType);genericMethod.Invoke(null, new object[] { app, requestType.Name });}}//为所有实现了INotification的消息类创建WebAAPI接口Type genericNotificationType = typeof(INotification);var publishMethodInfo = typeof(MediatorWebAPIExtensions).GetMethod("MapMediatorPublishApi", BindingFlags.NonPublic | BindingFlags.Static);foreach (var assembly in assemblies){//获取该程序集中所有实现了INotification的消息类类型var requestTypes = assembly.GetTypes().Where(type => !type.IsInterface && genericNotificationType.IsAssignableFrom(type));foreach (var requestType in requestTypes){//反射调用泛型映射WebApi方法var genericMethod = publishMethodInfo.MakeGenericMethod(requestType);genericMethod.Invoke(null, new object[] { app, requestType.Name });}}return app;}/// <summary>/// 为实现了IRequest<>的消息类为映射为WebAPI接口,根据消息类名称生成对应的CRUDD Http Method。/// </summary>/// <typeparam name="TRequest"></typeparam>/// <typeparam name="TResponse"></typeparam>/// <param name="app"></param>/// <param name="requestTypeName"></param>internal static void MapMediatorSendApi<TRequest, TResponse>(IEndpointRouteBuilder app, string requestTypeName) where TRequest : IRequest<TResponse>{if (requestTypeName.StartsWith("Create")) //Http Post{var uri = new Uri(requestTypeName.Replace("Create", ""), UriKind.Relative);app.MapPost(uri.ToString(), async ([FromServices] IMediator mediator, [FromBody] TRequest request) =>{TResponse response = await mediator.Send(request);return Results.Created(uri, response);}).WithName(requestTypeName).WithOpenApi();}else if (requestTypeName.StartsWith("Read")) //Http Get{var uri = new Uri(requestTypeName.Replace("Read", ""), UriKind.Relative);app.MapGet(uri.ToString(), async ([FromServices] IMediator mediator, [FromBody] TRequest request) =>{TResponse response = await mediator.Send(request);return Results.Ok(response);}).WithName(requestTypeName).WithOpenApi();}else if (requestTypeName.StartsWith("Update")) //Http Put{var uri = new Uri(requestTypeName.Replace("Update", ""), UriKind.Relative);app.MapPut(uri.ToString(), async ([FromServices] IMediator mediator, [FromBody] TRequest request) =>{TResponse response = await mediator.Send(request);return Results.Ok(response);}).WithName(requestTypeName).WithOpenApi();}else if (requestTypeName.StartsWith("Delete")) //Http Delete{var uri = new Uri(requestTypeName.Replace("Delete", ""), UriKind.Relative);app.MapDelete(uri.ToString(), async ([FromServices] IMediator mediator, [FromBody] TRequest request) =>{TResponse response = await mediator.Send(request);return Results.NoContent();}).WithName(requestTypeName).WithOpenApi();}else  //如不匹配则生成MediatR Send WebAPI接口{app.MapPost("/mediatr/send/" + requestTypeName, async ([FromServices] IMediator mediator, [FromBody] TRequest request) =>{TResponse response = await mediator.Send(request);return Results.Ok(response);}).WithName(requestTypeName).WithOpenApi();}}/// <summary>/// 为实现了INotification的消息类映射WebAPI接口。/// </summary>/// <typeparam name="TNotification"></typeparam>/// <param name="app"></param>/// <param name="requestTypeName"></param>internal static void MapMediatorPublishApi<TNotification>(IEndpointRouteBuilder app, string requestTypeName) where TNotification : INotification{app.MapPost("/mediatr/publish/" + requestTypeName, async ([FromServices] IMediator mediator, [FromBody] TNotification notification) =>{await mediator.Publish(notification);return Results.Ok();}).WithName(requestTypeName).WithOpenApi();}}
}

如上就是实现这个功能的所有代码,为了让大家看明白,我加了很多注释。如果哪位小伙伴还不明白就在下面留言。这些代码最难的地方就是对于泛型接口的处理。

我的示例项目如下,代码已经上传到了GitHub :iamxiaozhuang/MediatRWebAPI (github.com)  大家随便用。

8d60076a300e48efc0f66931a0d84266.png

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

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

相关文章

bupt summer training for 16 #8 ——字符串处理

https://vjudge.net/contest/175596#overview A.设第i次出现的位置左右端点分别为Li&#xff0c;Ri 初始化L0 0&#xff0c;则有ans sum{ (L[i] - L[i-1]) * (n 1 - Ri) } 1 #include <cstdio>2 #include <cstring>3 #include <iostream>4 #include <a…

程序员必须知道的HTML常用代码有哪些?

HTML即超文本标记语言&#xff0c;是目前应用最为广泛的语言之一&#xff0c;是组成一个网页的主要语言。在现今这个HTML5华丽丽地占领了整个互联网的时候&#xff0c;如果想要通过网页抓住浏览者的眼球光靠因循守旧是不行的&#xff0c;程序猿们需要掌握一些必须知道的HTML常用…

公用ip地址查询_是什么使您无法更改公用IP地址并在Internet上造成严重破坏?

公用ip地址查询What exactly is preventing you (or anyone else) from changing their IP address and causing all sorts of headaches for ISPs and other Internet users? 到底是什么在阻止您(或其他任何人)更改其IP地址并导致ISP和其他Internet用户感到头疼&#xff1f; …

Vim的新一代补全插件:coc.nvim

coc.nvim可以同时在nvim和vim8.1上使用。 安装 参考官方&#xff1a;Install coc.nvim 推荐使用vim-plug插件管理器&#xff0c;在vimrc中添加&#xff1a; Plug neoclide/coc.nvim, {do: { -> coc#util#install()}} 然后输入命令:PlugInstall 等待插件下载&#xff0c;再等…

MySQL-02:“数据库”操作基本命令及权限笔记

目录 数据库操作 1、显示数据库 2、创建数据库 3、使用数据库 4、用户管理 5、授权管理 数据库操作 1、显示数据库 SHOW DATABASES; 默认数据库&#xff1a;   mysql - 用户权限相关数据   test - 用于用户测试数据   information_schema - MySQL本身架构相关数据…

C++STL——概述

一、相关介绍 STL 标准模板库在编写代码的过程中有一些程序经常会被用到&#xff0c;而且需求特别稳定&#xff0c;所以C中把这些常用的模板做了统一的规范&#xff0c;慢慢的就形成了STL提供三种类型的组件: 容器、迭代器和算法&#xff0c;它们都支持泛型程序设计标准容器 顺…

固态硬盘可靠性_您可以通过使用较少的总容量来提高硬盘的可靠性吗?

固态硬盘可靠性Your computer has a massive hard drive that you significantly underuse. Would decreasing the size of the primary partition actually increase the lifespan of the drive? 您的计算机具有大量未充分使用的巨大硬盘驱动器。 减小主分区的大小是否会真正…

接收上传的multi-file的文件(四)

构建工程 为例创建一个springmvc工程你需要spring-boot-starter-thymeleaf和 spring-boot-starter-web的起步依赖。为例能够上传文件在服务器&#xff0c;你需要在web.xml中加入标签做相关的配置&#xff0c;但在sringboot 工程中&#xff0c;它已经为你自动做了&#xff0c;所…

数据库读写分离 - MyBatis

2019独角兽企业重金招聘Python工程师标准>>> 由于项目中数据量较大&#xff0c;访问量也较高&#xff0c;故在数据库的设计上&#xff0c;采用读写分离思想&#xff0c;达到性能要求&#xff01; 简单科普一下实现读写分离的思路 配置及加载数据库信息&#xff0c;即…

MySQL-03:数据表操作基本命令笔记

目录 数据表 1、创建表 2、删除表 3、清空表 4、修改表 5、基本数据类型 数据表 1、创建表 create table 表名(列名 类型 是否可以为空&#xff0c;列名 类型 是否可以为空 )ENGINEInnoDB DEFAULT CHARSETutf8 是否可空&#xff0c;null表示空&#xff0c;非字符串n…

java 怎么调试到第三方库的内部,在有源码的情况下

第一步&#xff0c; 把第三方库加到workspace : https://stackoverflow.com/questions/370814/how-to-set-a-breakpoint-in-eclipse-in-a-third-party-library The most sure-fire way to do this (and end up with something thats actually useful) is to download the sou…

t-mobile频段_T-Mobile再次被黑客入侵:超过200万个帐号和地址可能泄漏

t-mobile频段Attackers may have compromised three percent of T-Mobile’s 77 million customers on Monday, revealing personal information like addresses, phone numbers, and account numbers. 周一&#xff0c;攻击者可能泄露了T-Mobile 7700万客户中的3&#xff05;&…

第二篇 第三章防火防烟分区检查(一)

仓库面积可以增加3倍 就是乘以4 要一定条件 : 第二篇 第三章防火防烟分区检查&#xff08;一&#xff09; 21分钟处 该题比较有代表性 停车库 耐火等级允许最大面积 民用建筑防火分区 防烟分区的划分    防火卷帘控制器的测试 防火阀 装在通风,空调系统中 只有连在风机主管…

高斯数学

伟大的数学家高斯在9岁那年&#xff0c;用很短的时间完成了从1到100的累加。那原本是老师给学生们出的难题&#xff0c;希望他们能老老实实地待在教室里。高斯的方法很简单&#xff0c;他发现这是50个101的求和&#xff1a;100&#xff0b;1、99&#xff0b;2、98&#xff0b;3…

Ant Design Blazor 发布 0.13.0,正式支持.NET 7!

时隔3个月&#xff0c;Ant Design Blazor 发布新功能版本 0.13.0&#xff0c;并正式支持.NET 7!大家快去访问 antblazor.com 体验吧&#xff01;&#x1f525; 新增 .NET 7 目标框架支持。#2810 ElderJames&#x1f525; 重构 Mentions 组件&#xff0c;修复定位和隐藏问题。#2…

gitlab 分支操作笔记\新建远程分支\抓取远程分支\复制远程\删除分支

密码重新输入与保存 git config --global http.emptyAuth truegit config --global credential.helper store 1.不复制远程&#xff0c;直接新建远程分支。&#xff08;非正规操作&#xff09; git init //初始化 git remote add origin http://****/*****/taskboard.git…

如何在Xbox One或PlayStation 4上为Skyrim特别版安装Mods

The Elder Scrolls V: Skyrim Special Edition is now available on PlayStation 4 and Xbox One, and for the first time, “mods” are available to console gamers. Elder Scrolls V&#xff1a;Skyrim特别版现已在PlayStation 4和Xbox One上可用&#xff0c;并且首次向主…

微软宣布:PowerBI 已经与 Office 整合,一切更简单,变革又来了

很多人认为 Office 是 Office&#xff0c;PowerBI 是 PowerBI&#xff0c;怎么在 PPT 中显示 PowerBI 呢&#xff1f;这种问题以后将再不会存在。微软已经宣布&#xff0c;PowerBI 已经与 Office 深度整合&#xff0c;在未来的企业中&#xff0c;PowerBI 将与 Word&#xff0c;…

066:ORM查询条件详解-startswith和endswith:

ORM查询条件详解-startswith和endswith&#xff1a; startswith&#xff1a;判断某个字段的值是否是以某个值开始的。大小写敏感。示例代码如下&#xff1a; articles1 Article.objects.filter(title__startswith"fuck") 以上代码的意思是提取所有标题以 fuck 字符串…

前端工程师面试题汇总

HTML Doctype作用&#xff1f;严格模式与混杂模式如何区分&#xff1f;它们有何意义? HTML5 为什么只需要写 <!DOCTYPE HTML>&#xff1f; 行内元素有哪些&#xff1f;块级元素有哪些&#xff1f; 空(void)元素有那些&#xff1f; 页面导入样式时&#xff0c;使用lin…