最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

Asp.Net Core控制器如何接收原始请求正文内容详解

来源:动视网 责编:小采 时间:2020-11-27 22:34:51
文档

Asp.Net Core控制器如何接收原始请求正文内容详解

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


没有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控制器如何接收原始请求正文内容详解

    Asp.Net Core控制器如何接收原始请求正文内容详解:主要目标 在Asp.net Core控制器中,通过自定义格式化程序来映射自定义处理控制器中的未知内容。本文将给大家详细介绍关于Asp.Net Core控制器接收原始请求正文内容的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 简单案例
    推荐度:
    标签: 请求 net core
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top