本文將介紹Xfrogcn.AspNetCore.Extensions擴充套件庫對於Http相關的其他功能擴充套件,這些功能旨在處理一些常見需求, 包括請求緩衝、請求頭傳遞、請求頭日誌範圍、針對HttpClient與HttpRequestMessage、HttpResponseMessage的擴充套件方法。
一、開啟服務端請求緩衝
ASP.NET Core 中請求體是不能多次讀取的,由於在MVC中,框架已經讀取過請求體,如果你在控制器中再次讀取,將會引發異常,如下示例:
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
public TestController()
{
}
[HttpPost]
public async Task<WeatherForecast> Save([FromBody]WeatherForecast enttiy)
{
using (StreamReader reader = new StreamReader(Request.Body))
{
Request.Body.Position = 0;
string response = await reader.ReadToEndAsync();
}
return enttiy;
}
}
當通過Post請求/test介面時,語句 Request.Body.Position 將觸發異常:
System.NotSupportedException: Specified method is not supported.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.set_Position(Int64 value)
當然,實際中可能不會像示例這樣處理請求,但在業務需求中,的確可能會有多次讀取請求體的情況出現。
通過開啟請求緩衝可以解決多次讀取請求體的問題,Xfrogcn.AspNetCore.Extensions擴充套件庫提供了EnableBufferingAttribute特性用於開啟請求緩衝,你可以將此特性用於控制器或者Action方法。
以上示例,只需在Save方法上新增EnableBuffering特性:
[HttpPost]
[EnableBuffering]
public async Task<WeatherForecast> Save([FromBody]WeatherForecast enttiy)
{
....
}
二、請求頭傳遞
微服務架構下,通常我們使用請求頭來實現請求的鏈路跟蹤以及日誌與請求的關聯,例如,通過x-request-id,在日誌系統中可以直接檢視某一個請求在所有服務中的相關日誌。
擴充套件庫通過攔截HttpClient請求管道,可實現對指定請求頭的自動傳遞。預設配置下,擴充套件庫會自動傳遞以"x-"開始的請求頭,如果你需要傳遞其他的請求頭,可通過配置中的TrackingHeaders來新增。
IServiceCollection services = new ServiceCollection()
.AddExtensions(null, config =>
{
// 自動傳遞以my-為字首的請求頭
config.TrackingHeaders.Add("my-*");
});
三、請求頭日誌的記錄
.NET Core日誌框架中,實現了日誌範圍的概念,通過日誌範圍,可以讓日誌系統記錄當前上下文的資訊,例如,ASP.NET Core MVC中,日誌範圍包含ActionContext相關資訊,故可以在一個請求的所有日誌中都可自動記錄Action的相關資訊。
擴充套件庫可以將配置的請求頭加入請求的日誌範圍,例如,預設配置下,擴充套件庫會將x-request-id加入到請求的日誌範圍,所以在單一請求中的所有日誌,都可自動攜帶x-request-id資訊,以此實現跨服務的日誌關聯。要包含其他的請求頭,可以通過配置中的HttpHeaders來設定:
IServiceCollection services = new ServiceCollection()
.AddExtensions(null, config =>
{
// 將my-id請求頭包含到日誌範圍
config.HttpHeaders.Add("my-id");
});
注意: 預設的控制檯日誌、檔案日誌不會儲存日誌範圍的相關資訊,你可以使用json格式的控制檯日誌或檔案日誌,在此格式下將儲存日誌範圍中的資料。
IServiceCollection services = new ServiceCollection()
.AddExtensions(null, config =>
{
config.ConsoleJsonLog = true;
});
四、Http訊息上的擴充套件方法
擴充套件庫在HttpRequestMessage上提供了GetObjectAsync、WriteObjectAsync擴充套件方法,以便於對請求訊息的讀寫。 在HttpResponseMessage上提供了GetObjectAsync、WriteObjectAsync擴充套件方法,以便於對應答訊息的讀寫。這些方法都採用json格式。
示例:
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
static async Task Main(string[] args)
{
IServiceCollection services = new ServiceCollection()
.AddExtensions(null, config =>
{
});
IServiceProvider serviceProvider = services.BuildServiceProvider();
IHttpClientFactory factory = serviceProvider.GetRequiredService<IHttpClientFactory>();
HttpClient client = factory.CreateClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5000/test");
// 寫入請求物件
await request.WriteObjectAsync(new WeatherForecast()
{
Date = DateTime.Now
});
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// 讀取請求物件
var entity = await request.GetObjectAsync<WeatherForecast>();
HttpResponseMessage response = await client.SendAsync(request);
// 讀取應答物件
entity = await response.GetObjectAsync<WeatherForecast>();
Console.ReadLine();
}
五、HttpClient上的擴充套件方法
為了更方便快捷地使用HttpClient,擴充套件庫在HttpClient上增加了多個擴充套件方法:
- PostAsync<TResponse>: 傳送物件到服務端,並獲取指定型別的應答
- PostAsync: 傳送物件到服務端,並獲取應答字串
- GetAsync<TResponse>: 傳送Get請求,並獲取TResponse型別的應答
- GetAsync: 傳送Get請求,並獲取String型別的應答
- SubmitFormAsync<TResponse>: 向伺服器提交表單資料,並獲取TResponse型別的應答
- SubmitFormAsync: 向伺服器提交表單資料,並獲取String型別的應答
- UploadFileAsync<TResponse>: 上次本地檔案
- UploadStreamAsync<TResponse>: 上傳流資料到伺服器