Asp.Net Core控制器如何接收原始请求正文内容详解
 更新时间:2018年09月04日 14:42:09   作者:范存威  

这篇文章主要给大家介绍了关于Asp.Net Core控制器如何接收原始请求正文内容的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

主要目标

在Asp.net Core控制器中,通过自定义格式化程序来映射自定义处理控制器中的“未知”内容。本文将给大家详细介绍关于Asp.Net Core控制器接收原始请求正文内容的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧
简单案例

为了演示这个问题,我们用VS2017创建一个默认的Asp.net Core Web Api项目。

[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请求

我们从最常见的json输入请求开始。

User-Agent: Fiddler
Host: localhost:5000
Content-Type: application/json
Content-Length: 16

请求body:

{“123456”}

通过后台调试和fiddler抓包,我们可以看到请求输入和返回。

后台调试,查看请求输入结果

fiddler查看请求header

fiddler查看返回结果

注意!!

别忘了[FromBody],有时候会忘的。
后台action接收类型为string的时候,请求body只能是字符串,不能传json对象。我演示这个例子时,被这点坑了。如果接收对象是一个类的时候,才可以传json对象。

没有JSON

虽然传输json数据是最常用的,但有时候我们需要支持普通的文本或者二进制信息。我们将Content-Type改为
text/plain

User-Agent: Fiddler
Host: localhost:5000
Content-Type:text/plain
Content-Length: 16

请求body:

{“123456”}

悲剧的事情来,报404!

不支持text/plain

事情到此就变得稍微复杂了一些,因为asp.netcore只处理它认识的类型,如json和formdata。默认情况下,原始数据不能直接映射到控制器参数。这是个小坑,不知你踩到过没有?仔细想想,这是有道理的。MVC具有特定内容类型的映射,如果您传递的数据不符合这些内容类型,则无法转换数据,因此它假定没有匹配的端点可以处理请求。
那么怎么支持原始的请求映射呢?
支持原始正文请求

不幸的是,ASP.NET Core不允许您仅通过方法参数以任何有意义的方式捕获“原始”数据。无论如何,您需要对其进行一些自定义处理Request.Body以获取原始数据,然后对其进行反序列化。
您可以捕获原始数据Request.Body并从中直接读取原始缓冲区。
最简单,最不易侵入,但不那么明显的方法是使用一个方法接受没有参数的 POST或PUT数据,然后从Request.Body以下位置读取原始数据:
读取字符串缓冲区

[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

要读取二进制数据,你可以使用以下内容:
读取byte缓冲区

[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
}
}

查看执行结果

接收文本内容

接收二进制数据

HttpRequest静态扩展

如果你为了方便,写了很多HttpRequest的扩展,接收参数时,可以看起来更简洁一些。

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>
/// 二进制
/// </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();
}

自动转换文本和二进制值

上面虽然解决了原始参数转换问题,但不够友好。如果你打算像原生MVC那样自动映射参数的话,你需要做一些自定义格式化适配。
创建一个Asp.net MVC InputFormatter

ASP.NET Core使用一种干净且更通用的方式来处理内容的自定义格式InputFormatter。输入格式化程序挂钩到请求处理管道,让您查看特定类型的内容以确定是否要处理它。然后,您可以阅读请求正文并对入站内容执行自己的反序列化。

InputFormatter有几个要求

您需要使用[FromBody]去获取
您必须能够查看请求并确定是否以及如何处理内容。

在这个例子中,对于“原始内容”,我想查看具有以下类型的请求:

text/plain(文本)
appliaction/octet-stream(byte[])
没有内容类型(string)

要创建格式化程序,你可以实现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()检查对内容类型的请求以支持,然后将ReadRequestBodyAsync()内容读取和反序列化为应在控制器方法的参数中返回的结果类型。
InputFormatter必须在ConfigureServices()启动代码中注册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;
}

然后你就可以发送post请求,像这样:

User-Agent: Fiddler
Host: localhost:5000
Content-Length: 6

或者

User-Agent: Fiddler
Host: localhost:5000
Content-Type:text/plain
Content-Length: 6

请注意,您可以使用内容类型调用相同的控制器方法application/json并传递JSON字符串,这也将起作用。在RawRequestBodyFormatter 简单地增加它支持的附加内容类型的支持。
二进制数据

[HttpPost]
[Route(“PostBinaryPlus”)]
public byte[] PostBinaryPlus([FromBody] byte[] value)
{
return value;
}

请求内容如下:

User-Agent: Fiddler
Host: localhost:5000
Content-Length: 6
Content-Type: application/octet-stream

源代码

示例代码已上传到 CsharpFanDemo (本地下载)
参考链接

本文包含翻译和自己实践。主要思路和代码来源于以下链接:
Accepting Raw Request Body Content in ASP.NET Core API Controllers
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对华域联盟的支持。

您可能感兴趣的文章:Asp.net Core MVC中怎么把二级域名绑定到特定的控制器上详解如何在ASP.NET Core中编写高效的控制器ASP.NET Core MVC解决控制器同名Action请求不明确的问题

core
控制器
原始请求

相关文章
Asp.Net Mvc2 增删改查DEMO附下载接触mvc也有一段时间了(2.0),也看到园子里很多人在学习,自己也在园子里面看过前辈们写的博客,确实受益匪浅。本文写的都是基础中的基础,仅供想学习MVC的新手们入门之作 2012-04-04
asp.net 数据访问层 存储过程分页语句在asp.net 网页中如果在业务逻辑层分页在使用PagedDataSource对象,但如果数据记录过多,使用它会严重的损害应用程序的性能. 2009-12-12
ASP.NET 图片加水印防盗链实现代码ASP.NET 图片加水印防盗链实现代码,需要的朋友可以参考下。 2011-12-12
ASP.NET Core Web App应用第三方Bootstrap模板的方法教程这篇文章主要给大家介绍了关于ASP.NET Core Web App应用第三方Bootstrap模板的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧 2018-06-06
asp.net基于JWT的web api身份验证及跨域调用实践这篇文章主要介绍了asp.net基于JWT的web api身份验证及跨域调用实践,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 2018-07-07
Web Services使用多态的方法Web Services可以支持多态,不过仅仅限制在可以直接引用Web Services的时候,本文也只是起到抛砖引玉的效果, 2015-10-10
Asp.Net如何将多个RadioButton指定在一个组中将多个RadioButton指定在一个组中,实现其实很简单,一句代码即可,具体如下,希望对大家有所帮助 2013-12-12
压缩aspx页面删除多余空格的两种方法这篇文章主要介绍了压缩aspx页面移除多余空格的两种方法,可以在发布页面之前压缩aspx,无须浪费web server的cpu,需要的朋友可以参考下 2014-02-02
.NET异步编程总结—-四种实现模式代码总结本篇文章主要介绍了.NET异步编程总结—-四种实现模式,详细的介绍了每种方法的实现和实例,具有一定的参考价值,有兴趣的可以了解一下。
2016-12-12
ASP.NET MVC实现批量文件上传这篇文章主要为大家详细介绍了ASP.NET MVC实现批量文件上传,简单介绍单文件上传的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 2018-09-09

最新评论

声明:本站(华域联盟www.cnhackhy.com)所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。