如何在ASP.NET Core控制器中接收“多部分/混合" [英] How to receive `multipart/mixed` in an ASP.NET Core controller
问题描述
旧版系统会向我发送此信息:
POST/xml HTTP/1.1主机:localhost:9000用户代理:curl/7.64.1接受: */*内容长度:321内容类型:多部分/混合;边界= ------------------------ a9dd0ab37a224967-------------------------- a9dd0ab37a224967内容处置:附件;name ="part1"内容类型:text/xml< foo> bar</foo>-------------------------- a9dd0ab37a224967内容处置:附件;名称=第2部分"内容类型:application/json{'foo':'bar'}-------------------------- a9dd0ab37a224967--
我需要将第一部分解释为原始的 XElement
;在第二部分中,我需要常规的模型绑定.
我尝试:
class Part2 {公共字符串foo {get;放;}}[HttpPost][Route("/xml"))公共字符串Post1([FromBody] XElement part1,[FromBody] Part2 part2){返回part1.ToString()+,"+ part2.foo;}
但是ASP.NET不允许使用以 [FromBody]
装饰的参数.
如何使我的ASP.NET Core服务接收内容类型为 multipart/mixed
的http请求?
没有内置机制来处理这种类型的帖子数据( 您可以从端点调用此方法,如下所示: 您的端点将输出: 这时,您必须根据返回对象的属性反序列化. Legacy systems will send me this: The first part I need to interpret as raw I try this: But ASP.NET does not allow more than one parameter decorated with How do I make my ASP.NET Core service receive http requests with content-type There is no built-in mechanism to handle this type of post data ( I am going to assume that all the data that is coming in has a disposition of Take a look at this static helper: You can call this method from your endpoint, like so: Your endpoint would output: At this point, you'd have to deserialize based on the properties of the returned objects. 这篇关于如何在ASP.NET Core控制器中接收“多部分/混合"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! multipart/mixed
实际上具有无限的可能性,并且它将很难将其绑定到一般意义上),但是,您可以使用 使用Microsoft.AspNetCore.Http;使用Microsoft.AspNetCore.Http.Features;使用Microsoft.AspNetCore.WebUtilities;使用Microsoft.Net.Http.Headers;使用系统;使用System.Collections.Generic;使用System.IO;使用System.Net.Mime;使用System.Text;命名空间YourNamespace.Utilities{公共静态类MutipartMixedHelper{公共静态异步IAsyncEnumerable< ParsedSection>ParseMultipartMixedRequestAsync(HttpRequest请求){//提取,清理和验证边界var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(request.ContentType).Boundary).Value;如果(string.IsNullOrWhiteSpace(boundary)||(boundary.Length> new FormOptions().MultipartBoundaryLengthLimit)){抛出新的InvalidDataException(边界被射击");}//根据边界创建一个新的阅读器var reader = new MultipartReader(boundary,request.Body);//从MultipartReader开始阅读各节,直到没有更多内容为止MultipartSection部分;while((section =等待reader.ReadNextSectionAsync())!= null){//解析内容类型var contentType = new ContentType(section.ContentType);//创建一个新的ParsedSecion并开始填写详细信息var parsedSection =新的ParsedSection{IsJson = contentType.MediaType.Equals("application/json",StringComparison.OrdinalIgnoreCase),IsXml = contentType.MediaType.Equals("text/xml",StringComparison.OrdinalIgnoreCase),编码= Encoding.GetEncoding(contentType.CharSet)};//必须为XML或JSONif(!parsedSection.IsXml&!parsedSection.IsJson){抛出新的InvalidDataException(仅处理json/xml");}//解析内容如果(ContentDispositionHeaderValue.TryParse(section.ContentDisposition,输出为var contentDisposition)&&contentDisposition.DispositionType.Equals("attachment")){//保存名称parsedSection.Name = contentDisposition.Name.Value;//使用正确的编码创建一个新的StreamReader//将基础流保持打开状态使用(var streamReader = new StreamReader(section.Body,parsedSection.Encoding,leaveOpen:true)){parsedSection.Data =等待streamReader.ReadToEndAsync();收益回报parsedSection;}}}}}公共密封类ParsedSection{公共布尔IsJson {get;放;}公共布尔IsXml {get;放;}公共字符串名称{get;放;}公用字串Data {get;放;}公共编码编码{get;放;}}}
[HttpPost,Route("TestMultipartMixedPost"))]公共异步Task< IActionResult>考验我(){等待foreach(MutipartMixedHelper中的var parsedSection.ParseMultipartMixedRequestAsync(Request)){Debug.WriteLine($名称:{parsedSection.Name}"));Debug.WriteLine($"Encoding:{parsedSection.Encoding.EncodingName}");Debug.WriteLine($"IsJson:{parsedSection.IsJson}");Debug.WriteLine($"IsXml:{parsedSection.IsXml}");Debug.WriteLine($"Data:{parsedSection.Data}");Debug.WriteLine("-----------------------");}返回Ok();}
名称:part1编码:Unicode(UTF-8)IsJson:错IsXml:正确数据:< foo> bar</foo>-----------------------名称:part2编码:Unicode(UTF-8)IsJson:正确IsXml:错误数据:{"foo":"bar"}-----------------------
POST /xml HTTP/1.1
Host: localhost:9000
User-Agent: curl/7.64.1
Accept: */*
Content-Length: 321
Content-Type: multipart/mixed; boundary=------------------------a9dd0ab37a224967
--------------------------a9dd0ab37a224967
Content-Disposition: attachment; name="part1"
Content-Type: text/xml
<foo>bar</foo>
--------------------------a9dd0ab37a224967
Content-Disposition: attachment; name="part2"
Content-Type: application/json
{'foo': 'bar'}
--------------------------a9dd0ab37a224967--
XElement
; for the second part I would like the usual model binding.class Part2 {
public string foo { get; set; }
}
[HttpPost]
[Route("/xml")]
public string Post1([FromBody] XElement part1, [FromBody] Part2 part2 )
{
return part1.ToString() + ", " + part2.foo;
}
[FromBody]
.multipart/mixed
?multipart/mixed
has virtually unlimited possibilities, and it would be hard to bind to it in a generic sense), but, you can easily parse the data yourself using the MultipartReader
object.attachment
and that only JSON and XML content-types are valid. But this should be open-ended enough for you to modify as you see fit.using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Mime;
using System.Text;
namespace YourNamespace.Utilities
{
public static class MutipartMixedHelper
{
public static async IAsyncEnumerable<ParsedSection> ParseMultipartMixedRequestAsync(HttpRequest request)
{
// Extract, sanitize and validate boundry
var boundary = HeaderUtilities.RemoveQuotes(
MediaTypeHeaderValue.Parse(request.ContentType).Boundary).Value;
if (string.IsNullOrWhiteSpace(boundary) ||
(boundary.Length > new FormOptions().MultipartBoundaryLengthLimit))
{
throw new InvalidDataException("boundry is shot");
}
// Create a new reader based on that boundry
var reader = new MultipartReader(boundary, request.Body);
// Start reading sections from the MultipartReader until there are no more
MultipartSection section;
while ((section = await reader.ReadNextSectionAsync()) != null)
{
// parse the content type
var contentType = new ContentType(section.ContentType);
// create a new ParsedSecion and start filling in the details
var parsedSection = new ParsedSection
{
IsJson = contentType.MediaType.Equals("application/json",
StringComparison.OrdinalIgnoreCase),
IsXml = contentType.MediaType.Equals("text/xml",
StringComparison.OrdinalIgnoreCase),
Encoding = Encoding.GetEncoding(contentType.CharSet)
};
// Must be XML or JSON
if (!parsedSection.IsXml && !parsedSection.IsJson)
{
throw new InvalidDataException("only handling json/xml");
}
// Parse the content disosition
if (ContentDispositionHeaderValue.TryParse(
section.ContentDisposition, out var contentDisposition) &&
contentDisposition.DispositionType.Equals("attachment"))
{
// save the name
parsedSection.Name = contentDisposition.Name.Value;
// Create a new StreamReader using the proper encoding and
// leave the underlying stream open
using (var streamReader = new StreamReader(
section.Body, parsedSection.Encoding, leaveOpen: true))
{
parsedSection.Data = await streamReader.ReadToEndAsync();
yield return parsedSection;
}
}
}
}
}
public sealed class ParsedSection
{
public bool IsJson { get; set; }
public bool IsXml { get; set; }
public string Name { get; set; }
public string Data { get; set; }
public Encoding Encoding { get; set; }
}
}
[HttpPost, Route("TestMultipartMixedPost")]
public async Task<IActionResult> TestMe()
{
await foreach (var parsedSection in MutipartMixedHelper
.ParseMultipartMixedRequestAsync(Request))
{
Debug.WriteLine($"Name: {parsedSection.Name}");
Debug.WriteLine($"Encoding: {parsedSection.Encoding.EncodingName}");
Debug.WriteLine($"IsJson: {parsedSection.IsJson}");
Debug.WriteLine($"IsXml: {parsedSection.IsXml}");
Debug.WriteLine($"Data: {parsedSection.Data}");
Debug.WriteLine("-----------------------");
}
return Ok();
}
Name: part1
Encoding: Unicode (UTF-8)
IsJson: False
IsXml: True
Data: <foo>bar</foo>
-----------------------
Name: part2
Encoding: Unicode (UTF-8)
IsJson: True
IsXml: False
Data: {"foo": "bar"}
-----------------------