我正在(尝试)将ASP.NET核心应用程序从.NET CoreApp3.1升级到.NET 6,但是有一次测试失败了,无法对问题结果进行反序列化。失败的原因是在.NET 6中,内容类型是application/problem+json
,而在.NET核心应用程序3.1 application/xml
中。
已经在迁移文档中搜索了与此有关的任何注释,但是什么都找不到。
在我的GitHub中有一个repro,控制器非常简单
using System.Net.Mime;
using Microsoft.AspNetCore.Mvc;
namespace ProblemDetailsXMLSerialization
{
[ApiController]
[Route("[controller]")]
public class XmlController : ControllerBase
{
[HttpPost]
[Produces(MediaTypeNames.Application.Xml)]
[Consumes(MediaTypeNames.Application.Xml)]
public IActionResult Xml()
{
return Problem();
}
}
}
// Test file
using Microsoft.AspNetCore.Mvc.Testing;
using ProblemDetailsXMLSerialization;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace TestProject1
{
public class UnitTest1
{
[Fact]
public async Task Test1()
{
// Arrange
var application = new WebApplicationFactory<Startup>();
var client = application.CreateClient();
// Act
const string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>";
var content = new StringContent(xml, Encoding.UTF8, MediaTypeNames.Application.Xml);
var response = await client.PostAsync("xml", content);
// Assert
Assert.Equal(MediaTypeNames.Application.Xml, response.Content.Headers.ContentType.MediaType);
var responseString = await response.Content.ReadAsStringAsync();
}
}
}
谢谢
发布于 2022-11-28 21:41:33
要获得一个XML
响应--匹配您的assert语句--您需要添加一个带有值application/xml
的Accept
HTTP报头。
来自文档
当客户端指定
Accept
标头时,内容协商就会发生。ASP.NET Core使用的默认格式是JSON
。
var content = new StringContent(xml, Encoding.UTF8, MediaTypeNames.Application.Xml);
client.DefaultRequestHeaders.Add(
"Accept", "application/xml"
);
var response = await client.PostAsync("xml", content);
Accept
和application/xml
都有内置字符串。
client.DefaultRequestHeaders.Add(
Microsoft.Net.Http.Headers.HeaderNames.Accept,
System.Net.Mime.MediaTypeNames.Application.Xml
);
将标头设置为DefaultRequestHeaders
使其与该HttpClient
实例发出的每个请求一起发送。
如果您只需要一个请求/只需要它,那么使用一个HttpRequestMessage
实例。
using (var request = new HttpRequestMessage(HttpMethod.Post, "xml"))
{
request.Headers.Add("accept", "application/xml");
request.Content = new StringContent(xml, Encoding.UTF8, MediaTypeNames.Application.Xml);
var response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
}
在这两种情况下,responseString
变量都将包含类似于下面的有效负载。
<problem xmlns="urn:ietf:rfc:7807">
<status>500</status>
<title>An error occurred while processing your request.</title>
<type>https://tools.ietf.org/html/rfc7231#section-6.6.1</type>
<traceId>00-26c29d0830bd0a5a417e9bab9746bd23-3cfbc9589ffd8182-00</traceId>
</problem>
发布于 2022-11-29 13:52:44
TLDR
若要修复此问题,请更改注册XmlOutput格式化程序的顺序。把它调到第一位置。在启动services.AddControllers().AddXmlSerializerFormatters()之后,将XmlFormatter设置为第一个位置。还没有尝试过这段代码,但是这样的代码应该可以工作:
services.AddControllers().AddXmlSerializerFormatters();
services.Configure<MvcOptions>(options => {
var xmlFormatterIdx = options.OutputFormatters.length - 1;
options.OutputFormatters.Insert(0,
options.OutputFormatters[xmlFormatterIdx]);
options.OutputFormatters.RemoveAt(xmlFormatterIdx + 1);
});
详细信息
当使用"Produces“属性时,这应该是响应类型。在这种情况下,dotnet如何处理包含ProblemDetail响应的对象结果似乎是一个问题。因此,这就是我在反编译和检查源代码时看到的情况:
结论
produces属性应该覆盖它,但是它没有覆盖它。dotnet中的当前实现给出了输出格式化程序注册的顺序,具有更高的优先级。
可能是应该以不同的方式执行DefaultOutputformatter实现,并将对象结果的内容类型作为响应类型的顺序来使用,而不是如何注册输出处理程序。不确定副作用可能是什么,但这可能是dotnet团队需要研究的问题。
https://stackoverflow.com/questions/72643642
复制相似问题