詳解C#如何自定義書寫中間件
一、什么是中間件
中間件是一種裝配到應(yīng)用管道以處理請(qǐng)求和響應(yīng)的軟件。是介于request與response處理過程之間的一個(gè)插件(一道處理過程),相對(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)求過來之后,我們想對(duì)這個(gè)請(qǐng)求做各種各樣的操作和記錄,這個(gè)時(shí)候我們可以加入中間件。目的就是對(duì)這個(gè)請(qǐng)求和響應(yīng)做處理,其實(shí)不難理解,這就是類似于工業(yè)機(jī)器,一個(gè)商品出來之前會(huì)有很多關(guān)卡,會(huì)執(zhí)行N到工序。最后加工出來的產(chǎn)品就是我們想要的,也是安全的。這些關(guān)卡就類似于中間件的作用了。
微軟約定中間件需要兩個(gè)參數(shù),一個(gè)是httpcontext上下文對(duì)象,一個(gè)是Task類型的委托。通過上下文對(duì)象,處理請(qǐng)求,通過委托傳遞上下文對(duì)象到下一個(gè)中間件。核心就是一系列的請(qǐng)求委托,Run、Use、Map
- Run:是最后一道工序,管道末尾。
- Use:連接請(qǐng)求委托,next 向下走。
- Map:擴(kuò)展用作約定創(chuàng)建管道分支。
三、定義中間件
中間件的處理流程就像一個(gè)俄羅斯套娃,微軟約定中間件需要兩個(gè)參數(shù),一個(gè)是httpcontext上下文對(duì)象,一個(gè)是Task類型的委托。通過上下文對(duì)象,處理請(qǐng)求,通過委托傳遞上下文對(duì)象到下一個(gè)中間件,這也是套娃模式的由來。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)
{
/*
* 在這里可以書寫業(yè)務(wù)處理邏輯
*中間件的處理流程就像一個(gè)俄羅斯套娃,微軟約定中間件需要兩個(gè)參數(shù),一個(gè)是httpcontext上下文對(duì)象,一個(gè)是Task類型的委托。
* 通過上下文對(duì)象,處理請(qǐng)求,通過委托傳遞上下文對(duì)象到下一個(gè)中間件(這也是套娃模式的由來)。
*/
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 = "拒絕訪問";
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è)中間件拓展類,為每個(gè)自定義中間件創(chuàng)建方法,通過IApplicationBuilder拓展方法暴露
/// <summary>
/// 中間件拓展類
/// </summary>
public static class MyMiddlewareExtensions
{
/// <summary>
/// 將封裝的中間件委托到一個(gè)類中,通過IApplicationBuilder拓展方法暴露
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IApplicationBuilder UseMyMiddlewareOne(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyMiddleware>();
}
/*
* 下面還可以拓展其他自定義中間件方法,通過IApplicationBuilder暴露
*/
}四、配置使用中間件
使用中間件
注意:使用中間件,順序非常重要。比如此處,要放在權(quán)限處理的前面。不然請(qǐng)求從管道回來的時(shí)候,會(huì)先走消息處理,然后再判斷權(quán)限,這樣的話就無法處理了。因?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();
//開發(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#如何自定義書寫中間件的文章就介紹到這了,更多相關(guān)C#中間件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#代碼實(shí)現(xiàn)短信驗(yàn)證碼接口示例
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)短信驗(yàn)證碼接口示例代碼,感興趣的小伙伴們可以參考一下2016-08-08
C#使用隊(duì)列(Queue)解決簡單的并發(fā)問題
這篇文章主要介紹了使用隊(duì)列(Queue)解決簡單的并發(fā)問題,講解的很細(xì)致,喜歡的朋友們可以了解一下2015-07-07
C#正則表達(dá)式分解和轉(zhuǎn)換IP地址實(shí)例(C#正則表達(dá)式大全 c#正則表達(dá)式語法)
這是我發(fā)了不少時(shí)間整理的C#的正則表達(dá)式,新手朋友注意一定要手冊(cè)一下哦,這樣可以節(jié)省很多寫代碼的時(shí)間。下面進(jìn)行了簡單總結(jié)2013-12-12
C#組件系列 你值得擁有的一款Excel處理神器Spire.XLS
又一款Excel處理神器Spire.XLS,這篇文章主要為大家詳細(xì)介紹了第三方組件Spire.XLS,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
C#裝飾器模式(Decorator Pattern)實(shí)例教程
這篇文章主要介紹了C#裝飾器模式(Decorator Pattern),以一個(gè)完整實(shí)例形式講述了C#裝飾器模式的實(shí)現(xiàn)過程,有助于深入理解C#程序設(shè)計(jì)思想,需要的朋友可以參考下2014-09-09

