Asp.Net Core控制器如何接收原始請(qǐng)求正文內(nèi)容詳解
主要目標(biāo)
在Asp.net Core控制器中,通過(guò)自定義格式化程序來(lái)映射自定義處理控制器中的“未知”內(nèi)容。本文將給大家詳細(xì)介紹關(guān)于Asp.Net Core控制器接收原始請(qǐng)求正文內(nèi)容的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧
簡(jiǎn)單案例
為了演示這個(gè)問(wèn)題,我們用VS2017創(chuàng)建一個(gè)默認(rèn)的Asp.net Core Web Api項(xiàng)目。
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase{
[HttpGet]
public ActionResult<string> Get() {
return "ok";
}
[HttpPost]
[Route("PostX")]
public ActionResult<string> Post([FromBody] string value)
{
return value;
}
}
Json請(qǐng)求
我們從最常見(jiàn)的json輸入請(qǐng)求開(kāi)始。
User-Agent: Fiddler Host: localhost:5000 Content-Type: application/json Content-Length: 16
請(qǐng)求body:
{"123456"}
通過(guò)后臺(tái)調(diào)試和fiddler抓包,我們可以看到請(qǐng)求輸入和返回。

后臺(tái)調(diào)試,查看請(qǐng)求輸入結(jié)果

fiddler查看請(qǐng)求header

fiddler查看返回結(jié)果
注意??!
別忘了[FromBody],有時(shí)候會(huì)忘的。
后臺(tái)action接收類(lèi)型為string的時(shí)候,請(qǐng)求body只能是字符串,不能傳json對(duì)象。我演示這個(gè)例子時(shí),被這點(diǎn)坑了。如果接收對(duì)象是一個(gè)類(lèi)的時(shí)候,才可以傳json對(duì)象。
沒(méi)有JSON
雖然傳輸json數(shù)據(jù)是最常用的,但有時(shí)候我們需要支持普通的文本或者二進(jìn)制信息。我們將Content-Type改為
text/plain
User-Agent: Fiddler Host: localhost:5000 Content-Type:text/plain Content-Length: 16
請(qǐng)求body:
{"123456"}
悲劇的事情來(lái),報(bào)404!

不支持text/plain
事情到此就變得稍微復(fù)雜了一些,因?yàn)閍sp.netcore只處理它認(rèn)識(shí)的類(lèi)型,如json和formdata。默認(rèn)情況下,原始數(shù)據(jù)不能直接映射到控制器參數(shù)。這是個(gè)小坑,不知你踩到過(guò)沒(méi)有?仔細(xì)想想,這是有道理的。MVC具有特定內(nèi)容類(lèi)型的映射,如果您傳遞的數(shù)據(jù)不符合這些內(nèi)容類(lèi)型,則無(wú)法轉(zhuǎn)換數(shù)據(jù),因此它假定沒(méi)有匹配的端點(diǎn)可以處理請(qǐng)求。
那么怎么支持原始的請(qǐng)求映射呢?
支持原始正文請(qǐng)求
不幸的是,ASP.NET Core不允許您僅通過(guò)方法參數(shù)以任何有意義的方式捕獲“原始”數(shù)據(jù)。無(wú)論如何,您需要對(duì)其進(jìn)行一些自定義處理Request.Body以獲取原始數(shù)據(jù),然后對(duì)其進(jìn)行反序列化。
您可以捕獲原始數(shù)據(jù)Request.Body并從中直接讀取原始緩沖區(qū)。
最簡(jiǎn)單,最不易侵入,但不那么明顯的方法是使用一個(gè)方法接受沒(méi)有參數(shù)的 POST或PUT數(shù)據(jù),然后從Request.Body以下位置讀取原始數(shù)據(jù):
讀取字符串緩沖區(qū)
[HttpPost]
[Route("PostText")]
public async Task<string> PostText()
{
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
return await reader.ReadToEndAsync();
}
}
這適用于一下Http和文本
User-Agent: Fiddler Host: localhost:5000 Content-Type: text/plain Content-Length: 6
要讀取二進(jìn)制數(shù)據(jù),你可以使用以下內(nèi)容:
讀取byte緩沖區(qū)
[HttpPost]
[Route("PostBinary")]
public async Task<byte[]> PostBinary()
{
using (var ms = new MemoryStream(2048))
{
await Request.Body.CopyToAsync(ms);
return ms.ToArray(); // returns base64 encoded string JSON result
}
}
查看執(zhí)行結(jié)果

接收文本內(nèi)容

接收二進(jìn)制數(shù)據(jù)
HttpRequest靜態(tài)擴(kuò)展
如果你為了方便,寫(xiě)了很多HttpRequest的擴(kuò)展,接收參數(shù)時(shí),可以看起來(lái)更簡(jiǎn)潔一些。
public static class HttpRequestExtension
{
/// <summary>
///
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static async Task<string> GetRawBodyStringFormater(this HttpRequest httpRequest, Encoding encoding)
{
if (encoding == null)
{
encoding = Encoding.UTF8;
}
using (StreamReader reader = new StreamReader(httpRequest.Body, encoding))
{
return await reader.ReadToEndAsync();
}
}
/// <summary>
/// 二進(jìn)制
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public static async Task<byte[]> GetRawBodyBinaryFormater(this HttpRequest httpRequest, Encoding encoding)
{
if (encoding == null)
{
encoding = Encoding.UTF8;
}
using (StreamReader reader = new StreamReader(httpRequest.Body, encoding))
{
using (var ms = new MemoryStream(2048))
{
await httpRequest.Body.CopyToAsync(ms);
return ms.ToArray(); // returns base64 encoded string JSON result
}
}
}
}
[HttpPost]
[Route("PostTextX")]
public async Task<string> PostTextX()
{
return await Request.GetRawBodyStringAsyn();
}
/// <summary>
/// 接收
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("PostBinaryX")]
public async Task<byte[]> PostBinaryX()
{
return await Request.GetRawBodyBinaryAsyn();
}
自動(dòng)轉(zhuǎn)換文本和二進(jìn)制值
上面雖然解決了原始參數(shù)轉(zhuǎn)換問(wèn)題,但不夠友好。如果你打算像原生MVC那樣自動(dòng)映射參數(shù)的話,你需要做一些自定義格式化適配。
創(chuàng)建一個(gè)Asp.net MVC InputFormatter
ASP.NET Core使用一種干凈且更通用的方式來(lái)處理內(nèi)容的自定義格式InputFormatter。輸入格式化程序掛鉤到請(qǐng)求處理管道,讓您查看特定類(lèi)型的內(nèi)容以確定是否要處理它。然后,您可以閱讀請(qǐng)求正文并對(duì)入站內(nèi)容執(zhí)行自己的反序列化。
InputFormatter有幾個(gè)要求
- 您需要使用[FromBody]去獲取
- 您必須能夠查看請(qǐng)求并確定是否以及如何處理內(nèi)容。
在這個(gè)例子中,對(duì)于“原始內(nèi)容”,我想查看具有以下類(lèi)型的請(qǐng)求:
- text/plain(文本)
- appliaction/octet-stream(byte[])
沒(méi)有內(nèi)容類(lèi)型(string)
要?jiǎng)?chuàng)建格式化程序,你可以實(shí)現(xiàn)IInputFormatter或者從InputFormatter繼承。
public class RawRequestBodyFormatter : IInputFormatter
{
public RawRequestBodyFormatter()
{
}
public bool CanRead(InputFormatterContext context)
{
if (context == null) throw new ArgumentNullException("argument is Null");
var contentType = context.HttpContext.Request.ContentType;
if (string.IsNullOrEmpty(contentType) || contentType == "text/plain" || contentType == "application/octet-stream")
return true;
return false;
}
public async Task<InputFormatterResult> ReadAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
var contentType = context.HttpContext.Request.ContentType;
if (string.IsNullOrEmpty(contentType) || contentType.ToLower() == "text/plain")
{
using (StreamReader reader = new StreamReader(request.Body, Encoding.UTF8))
{
var content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}
if (contentType == "application/octet-stream")
{
using (StreamReader reader = new StreamReader(request.Body, Encoding.UTF8))
{
using (var ms = new MemoryStream(2048))
{
await request.Body.CopyToAsync(ms);
var content = ms.ToArray();
return await InputFormatterResult.SuccessAsync(content);
}
}
}
return await InputFormatterResult.FailureAsync();
}
}
格式化程序用于CanRead()檢查對(duì)內(nèi)容類(lèi)型的請(qǐng)求以支持,然后將ReadRequestBodyAsync()內(nèi)容讀取和反序列化為應(yīng)在控制器方法的參數(shù)中返回的結(jié)果類(lèi)型。
InputFormatter必須在ConfigureServices()啟動(dòng)代碼中注冊(cè)MVC :
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(o=>o.InputFormatters.Insert(0,new RawRequestBodyFormatter())).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
接受原始輸入
[HttpPost]
[Route("PostTextPlus")]
public string PostTextPlus([FromBody] string value)
{
return value;
}
然后你就可以發(fā)送post請(qǐng)求,像這樣:
User-Agent: Fiddler Host: localhost:5000 Content-Length: 6
或者
User-Agent: Fiddler Host: localhost:5000 Content-Type:text/plain Content-Length: 6
請(qǐng)注意,您可以使用內(nèi)容類(lèi)型調(diào)用相同的控制器方法application/json并傳遞JSON字符串,這也將起作用。在RawRequestBodyFormatter 簡(jiǎn)單地增加它支持的附加內(nèi)容類(lèi)型的支持。
二進(jìn)制數(shù)據(jù)
[HttpPost]
[Route("PostBinaryPlus")]
public byte[] PostBinaryPlus([FromBody] byte[] value)
{
return value;
}
請(qǐng)求內(nèi)容如下:
User-Agent: Fiddler Host: localhost:5000 Content-Length: 6 Content-Type: application/octet-stream
源代碼
示例代碼已上傳到 CsharpFanDemo (本地下載)
參考鏈接
本文包含翻譯和自己實(shí)踐。主要思路和代碼來(lái)源于以下鏈接:
Accepting Raw Request Body Content in ASP.NET Core API Controllers
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
asp.net網(wǎng)頁(yè)里面為什么找不到CS文件
這篇文章主要介紹了asp.net為什么網(wǎng)頁(yè)里面找不到CS文件,如何才能夠cs文件顯示出來(lái)2014-05-05
ASP.NET 2.0/3.5中直接操作Gridview控件插入新記錄
Gridview控件中并沒(méi)有提供像在FormView和DetailsView控件中那樣直接插入新記錄操作的支持。2008-11-11
.NET?Core部署為Windows服務(wù)的詳細(xì)步驟
這篇文章主要介紹了.NET?Core部署為Windows服務(wù),想要將.NET?Core部署為window服務(wù),項(xiàng)目中需要進(jìn)行以下配置:項(xiàng)目中引入Microsoft.Extensions.Hosting.WindowsServices包,本文給大家詳細(xì)講解,需要的朋友可以參考下2022-10-10
asp.net窗體的打開(kāi)和關(guān)閉(輸出js)
asp.net窗體的打開(kāi)和關(guān)閉(輸出js),需要的朋友可以參考下。2011-06-06
微信JS-SDK分享功能的.Net實(shí)現(xiàn)代碼
這篇文章主要介紹了微信JS-SDK分享功能的.Net實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-09-09
asp.net實(shí)現(xiàn)取消頁(yè)面表單內(nèi)文本輸入框Enter響應(yīng)的方法
這篇文章主要介紹了asp.net實(shí)現(xiàn)取消頁(yè)面表單內(nèi)文本輸入框Enter響應(yīng)的方法,結(jié)合實(shí)例形式分析了asp.net文本框Enter響應(yīng)的原理與取消Enter響應(yīng)的相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
asp.net分頁(yè)控件使用詳解【附實(shí)例下載】
本篇文章主要對(duì)asp.net創(chuàng)建事務(wù)的方法進(jìn)行實(shí)例介紹,具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12
ASP.NET實(shí)現(xiàn)從服務(wù)器下載文件問(wèn)題處理
本文主要介紹了ASP.NET實(shí)現(xiàn)從服務(wù)器下載文件問(wèn)題處理,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02

