根據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.pswp.cn/news/280937.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/280937.shtml
英文地址,請注明出處:http://en.pswp.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…