詳解C#如何自定義書(shū)寫(xiě)中間件
一、什么是中間件
中間件是一種裝配到應(yīng)用管道以處理請(qǐng)求和響應(yīng)的軟件。是介于request與response處理過(guò)程之間的一個(gè)插件(一道處理過(guò)程),相對(duì)比較輕量級(jí),并且在全局上會(huì)影響到request對(duì)象和response對(duì)象的屬性。因?yàn)楦淖兊氖侨郑孕枰?jǐn)慎實(shí)用,用不好會(huì)影響到性能。每個(gè)組件:
1、選擇是否將請(qǐng)求傳遞到管道中的下一個(gè)組件。
2、可在管道中的下一個(gè)組件前后執(zhí)行工作。
原理圖:
多個(gè)中間件時(shí),中間件請(qǐng)求和響應(yīng)的中間件順序相反

二、為什么使用中間件
在我們很多時(shí)候,當(dāng)一個(gè)請(qǐng)求過(guò)來(lái)之后,我們想對(duì)這個(gè)請(qǐng)求做各種各樣的操作和記錄,這個(gè)時(shí)候我們可以加入中間件。目的就是對(duì)這個(gè)請(qǐng)求和響應(yīng)做處理,其實(shí)不難理解,這就是類(lèi)似于工業(yè)機(jī)器,一個(gè)商品出來(lái)之前會(huì)有很多關(guān)卡,會(huì)執(zhí)行N到工序。最后加工出來(lái)的產(chǎn)品就是我們想要的,也是安全的。這些關(guān)卡就類(lèi)似于中間件的作用了。
微軟約定中間件需要兩個(gè)參數(shù),一個(gè)是httpcontext上下文對(duì)象,一個(gè)是Task類(lèi)型的委托。通過(guò)上下文對(duì)象,處理請(qǐng)求,通過(guò)委托傳遞上下文對(duì)象到下一個(gè)中間件。核心就是一系列的請(qǐng)求委托,Run、Use、Map
- Run:是最后一道工序,管道末尾。
- Use:連接請(qǐng)求委托,next 向下走。
- Map:擴(kuò)展用作約定創(chuàng)建管道分支。
三、定義中間件
中間件的處理流程就像一個(gè)俄羅斯套娃,微軟約定中間件需要兩個(gè)參數(shù),一個(gè)是httpcontext上下文對(duì)象,一個(gè)是Task類(lèi)型的委托。通過(guò)上下文對(duì)象,處理請(qǐng)求,通過(guò)委托傳遞上下文對(duì)象到下一個(gè)中間件,這也是套娃模式的由來(lái)。RequestDelegate是管道的核心。ApplicationBuilder就是接收了很多個(gè)RequestDelegae把它拼到一起。
定義
/// <summary>
/// 中間件定義和業(yè)務(wù)邏輯
/// </summary>
public class MyMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// 構(gòu)造
/// </summary>
/// <param name="next"></param>
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// 方法名必須命名為 Invoke或者 InvokeAsync,才能有效執(zhí)行下一個(gè)中間件
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
public async Task InvokeAsync(HttpContext httpContext)
{
/*
* 在這里可以書(shū)寫(xiě)業(yè)務(wù)處理邏輯
*中間件的處理流程就像一個(gè)俄羅斯套娃,微軟約定中間件需要兩個(gè)參數(shù),一個(gè)是httpcontext上下文對(duì)象,一個(gè)是Task類(lèi)型的委托。
* 通過(guò)上下文對(duì)象,處理請(qǐng)求,通過(guò)委托傳遞上下文對(duì)象到下一個(gè)中間件(這也是套娃模式的由來(lái))。
*/
try
{
await _next(httpContext);
}
catch (Exception ex)
{
//內(nèi)部出現(xiàn)異常
httpContext.Response.StatusCode = 500;
}
finally
{
var statusCode = httpContext.Response.StatusCode;
var msg = "";
switch (statusCode)
{
case 401:
msg = "未授權(quán)";
break;
case 403:
msg = "拒絕訪問(wèn)";
break;
case 404:
msg = "未找到服務(wù)";
break;
case 405:
msg = "405 Method Not Allowed";
break;
case 500:
msg = "服務(wù)器內(nèi)部錯(cuò)誤";
break;
case 502:
msg = "請(qǐng)求錯(cuò)誤";
break;
}
if (!string.IsNullOrWhiteSpace(msg))
{
await HandleExceptionAsync(httpContext, msg);
}
}
}
/// <summary>
/// 處理Http響應(yīng)異常
/// </summary>
/// <param name="httpContext"></param>
/// <param name="msg"></param>
/// <returns></returns>
private async Task HandleExceptionAsync(HttpContext httpContext, string msg)
{
ErrorModel error = new ErrorModel
{
code = httpContext.Response.StatusCode,
msg = msg
};
var result = JsonConvert.SerializeObject(error);
httpContext.Response.ContentType = "application/json;charset=utf-8";
await httpContext.Response.WriteAsync(result).ConfigureAwait(false);
}
}封裝拓展方法
創(chuàng)建一個(gè)中間件拓展類(lèi),為每個(gè)自定義中間件創(chuàng)建方法,通過(guò)IApplicationBuilder拓展方法暴露
/// <summary>
/// 中間件拓展類(lèi)
/// </summary>
public static class MyMiddlewareExtensions
{
/// <summary>
/// 將封裝的中間件委托到一個(gè)類(lèi)中,通過(guò)IApplicationBuilder拓展方法暴露
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseMyMiddlewareOne(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
/*
* 下面還可以拓展其他自定義中間件方法,通過(guò)IApplicationBuilder暴露
*/
}四、配置使用中間件
使用中間件
注意:使用中間件,順序非常重要。比如此處,要放在權(quán)限處理的前面。不然請(qǐng)求從管道回來(lái)的時(shí)候,會(huì)先走消息處理,然后再判斷權(quán)限,這樣的話就無(wú)法處理了。因?yàn)槭褂枚鄠€(gè)中間件時(shí),中間件請(qǐng)求和響應(yīng)的順序是相反的,此處還是爬樓看上面的原理圖比較清晰。
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//開(kāi)發(fā)環(huán)境使用
app.UseSwagger();
app.UseSwaggerUI(option =>
{
foreach (string version in typeof(ApiVersions).GetEnumNames())
{
option.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"版本:{version}");
}
});
}
app.UseRouting();
//使用自定義中間件:
app.UseMyMiddlewareOne();//注冊(cè)自定義中間件
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}五、演示
定義測(cè)試Http接口:
/// <summary>
/// 自定義中間件測(cè)試
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpGet]
public int MiddleWareTest(string param)
{
/*
* note:此處的字符串是否是數(shù)字不做判斷,當(dāng)輸入的非數(shù)字字符串時(shí),強(qiáng)轉(zhuǎn)Int服務(wù)內(nèi)部會(huì)
*/
int Number = int.Parse(param);
return Number;
}Http請(qǐng)求測(cè)試:

到此這篇關(guān)于詳解C#如何自定義書(shū)寫(xiě)中間件的文章就介紹到這了,更多相關(guān)C#中間件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#基于Modbus三種CRC16校驗(yàn)方法的性能對(duì)比
這篇文章主要介紹了C#基于Modbus三種CRC16校驗(yàn)方法的性能對(duì)比,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
DevExpress之ChartControl用法實(shí)例總結(jié)
這篇文章主要介紹了DevExpress之ChartControl用法實(shí)例總結(jié),需要的朋友可以參考下2014-08-08
C# 通過(guò)Socket讀取大量數(shù)據(jù)的示例
這篇文章主要介紹了C# 通過(guò)Socket讀取大量數(shù)據(jù)的示例,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03
利用C#與PLC通信實(shí)現(xiàn)設(shè)備遠(yuǎn)程控制與管理
PLC是工業(yè)自動(dòng)化中用于控制機(jī)械設(shè)備、生產(chǎn)線等的核心設(shè)備,通過(guò)與PLC的通信,我們可以實(shí)現(xiàn)設(shè)備的遠(yuǎn)程監(jiān)控、數(shù)據(jù)采集等功能,C#作為一種現(xiàn)代化的編程語(yǔ)言,能夠非常方便地與PLC進(jìn)行通信,本文將介紹如何利用C#與PLC進(jìn)行通信,并實(shí)現(xiàn)設(shè)備的遠(yuǎn)程控制與管理2025-02-02
C# 在項(xiàng)目中引用x86 x64的非托管代碼的方法
使用宏最簡(jiǎn)單的方法是編譯兩個(gè)版本,編譯多個(gè)版本可以點(diǎn)擊配置管理器,然后創(chuàng)建x86和x64,然后版本添加宏,這樣就可以判斷宏來(lái)使用不同的dll。這篇文章主要介紹了C# 在項(xiàng)目中引用x86 x64的非托管代碼的方法,需要的朋友可以參考下2018-03-03
C# WinForm開(kāi)發(fā)中使用XML配置文件實(shí)例
這篇文章主要介紹了C# WinForm開(kāi)發(fā)中使用XML配置文件實(shí)例,本文詳細(xì)講解了如何使用一個(gè)XML文件作為WinForm的配置文件,需要的朋友可以參考下2014-08-08

