Post XML 到 asp.net 核心 2.0 网络 api
Post XML to asp.net core 2.0 web api
我正在尝试 post XML 到 asp.net 核心 2:
$.ajax({
type: "POST",
url: 'api/Test',
data: "<test>hello<test>",
contentType: "application/xml",
success: function (response) { alert(response); },
});
我应该如何编写操作,以便它接受 xml 作为参数?
IActionResult Post([FromBody]string xml)
-> xml 为空
IActionResult Post([FromBody]XElement xml)
-> xml 为空
IActionResult Post(XElement xml)
->
InvalidOperationException:无法创建类型 'System.Xml.Linq.XElement' 的实例。模型绑定的复杂类型不能是抽象类型或值类型,并且必须具有无参数构造函数。
IActionResult Post(string xml)
-> xml 为空
在Startup.ConfigureServices中:
services.AddMvc()
.AddXmlSerializerFormatters();
如何编写控制器使其接受 XML 作为参数?我知道我可以从 HttpContext.Request 读取它,但我希望它成为参数
我最终创建了自定义 InputFormatter,这非常简单,但如果有更好的选择,非常欢迎您写下答案!
public class XDocumentInputFormatter : InputFormatter, IInputFormatter, IApiRequestFormatMetadataProvider
{
public XDocumentInputFormatter()
{
SupportedMediaTypes.Add("application/xml");
}
protected override bool CanReadType(Type type)
{
if (type.IsAssignableFrom(typeof(XDocument))) return true;
return base.CanReadType(type);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var xmlDoc = await XDocument.LoadAsync(context.HttpContext.Request.Body, LoadOptions.None, CancellationToken.None);
return InputFormatterResult.Success(xmlDoc);
}
}
在 startup.cs
中注册 XDocumentInputFormatter
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.InputFormatters.Insert(0, new XDocumentInputFormatter()));
}
只是对Liero给出的答案进行了更改,您应该使用StreamReader,这样您就可以支持多种编码。使用 UTF-8、UTF-16 和 ASCI 声明 header.
测试了我的解决方案
从 XDocumentInputFormatter 更改方法:
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var xmlDoc = await XDocument.LoadAsync(context.HttpContext.Request.Body, LoadOptions.None, CancellationToken.None);
return InputFormatterResult.Success(xmlDoc);
}
到下面
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context) {
// Use StreamReader to convert any encoding to UTF-16 (default C# and sql Server).
using (var streamReader = new StreamReader(context.HttpContext.Request.Body)) {
var xmlDoc = await XDocument.LoadAsync(streamReader, LoadOptions.None, CancellationToken.None);
return InputFormatterResult.Success(xmlDoc);
}
}
这些解决方案有效,但在 .NET Core 3 中有一个缺点 - 它们会导致异常(内部调用 XDocument.LoadAsync):
System.InvalidOperationException:不允许同步操作。改为调用 ReadAsync 或将 AllowSynchronousIO 设置为 true。
这是我使用 FileBufferingReadStream 修改后的解决方案(灵感来自 Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter)
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
Check.NotNull(context, nameof(context));
var xmlDoc = await LoadXmlFromRequestAsync(context.HttpContext);
return InputFormatterResult.Success(xmlDoc);
}
private static async Task<XDocument> LoadXmlFromRequestAsync(HttpContext httpContext)
{
Check.NotNull(httpContext, nameof(httpContext));
//Code from Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter to use FileBufferingReadStream to avoid synchronous read issue:
//https://github.com/dotnet/aspnetcore/issues/18723 - Synchronous call inside XDocument.LoadAsync causes --> System.InvalidOperationException: Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
int memoryThreshold = 30720;
long contentLength = httpContext.Request.ContentLength.GetValueOrDefault();
if (contentLength > 0 && contentLength < memoryThreshold)
{
memoryThreshold = (int)contentLength;
}
var readStream = new FileBufferingReadStream(httpContext.Request.Body, memoryThreshold);
httpContext.Response.RegisterForDispose(readStream);
await readStream.DrainAsync(CancellationToken.None);
readStream.Seek(0, SeekOrigin.Begin);
try
{
using (var streamReader = new StreamReader(readStream))
{
var xmlDoc = await XDocument.LoadAsync(streamReader, LoadOptions.None, CancellationToken.None);
return xmlDoc;
}
}
finally
{
await readStream.DisposeAsync();
}
}
我正在尝试 post XML 到 asp.net 核心 2:
$.ajax({
type: "POST",
url: 'api/Test',
data: "<test>hello<test>",
contentType: "application/xml",
success: function (response) { alert(response); },
});
我应该如何编写操作,以便它接受 xml 作为参数?
IActionResult Post([FromBody]string xml)
-> xml 为空IActionResult Post([FromBody]XElement xml)
-> xml 为空IActionResult Post(XElement xml)
-> InvalidOperationException:无法创建类型 'System.Xml.Linq.XElement' 的实例。模型绑定的复杂类型不能是抽象类型或值类型,并且必须具有无参数构造函数。IActionResult Post(string xml)
-> xml 为空
在Startup.ConfigureServices中:
services.AddMvc()
.AddXmlSerializerFormatters();
如何编写控制器使其接受 XML 作为参数?我知道我可以从 HttpContext.Request 读取它,但我希望它成为参数
我最终创建了自定义 InputFormatter,这非常简单,但如果有更好的选择,非常欢迎您写下答案!
public class XDocumentInputFormatter : InputFormatter, IInputFormatter, IApiRequestFormatMetadataProvider
{
public XDocumentInputFormatter()
{
SupportedMediaTypes.Add("application/xml");
}
protected override bool CanReadType(Type type)
{
if (type.IsAssignableFrom(typeof(XDocument))) return true;
return base.CanReadType(type);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var xmlDoc = await XDocument.LoadAsync(context.HttpContext.Request.Body, LoadOptions.None, CancellationToken.None);
return InputFormatterResult.Success(xmlDoc);
}
}
在 startup.cs
中注册 XDocumentInputFormatterpublic void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.InputFormatters.Insert(0, new XDocumentInputFormatter()));
}
只是对Liero给出的答案进行了更改,您应该使用StreamReader,这样您就可以支持多种编码。使用 UTF-8、UTF-16 和 ASCI 声明 header.
测试了我的解决方案从 XDocumentInputFormatter 更改方法:
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var xmlDoc = await XDocument.LoadAsync(context.HttpContext.Request.Body, LoadOptions.None, CancellationToken.None);
return InputFormatterResult.Success(xmlDoc);
}
到下面
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context) {
// Use StreamReader to convert any encoding to UTF-16 (default C# and sql Server).
using (var streamReader = new StreamReader(context.HttpContext.Request.Body)) {
var xmlDoc = await XDocument.LoadAsync(streamReader, LoadOptions.None, CancellationToken.None);
return InputFormatterResult.Success(xmlDoc);
}
}
这些解决方案有效,但在 .NET Core 3 中有一个缺点 - 它们会导致异常(内部调用 XDocument.LoadAsync):
System.InvalidOperationException:不允许同步操作。改为调用 ReadAsync 或将 AllowSynchronousIO 设置为 true。
这是我使用 FileBufferingReadStream 修改后的解决方案(灵感来自 Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter)
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
Check.NotNull(context, nameof(context));
var xmlDoc = await LoadXmlFromRequestAsync(context.HttpContext);
return InputFormatterResult.Success(xmlDoc);
}
private static async Task<XDocument> LoadXmlFromRequestAsync(HttpContext httpContext)
{
Check.NotNull(httpContext, nameof(httpContext));
//Code from Microsoft.AspNetCore.Mvc.Formatters.XmlSerializerInputFormatter to use FileBufferingReadStream to avoid synchronous read issue:
//https://github.com/dotnet/aspnetcore/issues/18723 - Synchronous call inside XDocument.LoadAsync causes --> System.InvalidOperationException: Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
int memoryThreshold = 30720;
long contentLength = httpContext.Request.ContentLength.GetValueOrDefault();
if (contentLength > 0 && contentLength < memoryThreshold)
{
memoryThreshold = (int)contentLength;
}
var readStream = new FileBufferingReadStream(httpContext.Request.Body, memoryThreshold);
httpContext.Response.RegisterForDispose(readStream);
await readStream.DrainAsync(CancellationToken.None);
readStream.Seek(0, SeekOrigin.Begin);
try
{
using (var streamReader = new StreamReader(readStream))
{
var xmlDoc = await XDocument.LoadAsync(streamReader, LoadOptions.None, CancellationToken.None);
return xmlDoc;
}
}
finally
{
await readStream.DisposeAsync();
}
}