首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >内容类型否定无法从netcoreapp3.1升级到net6 ASP.NET核心

内容类型否定无法从netcoreapp3.1升级到net6 ASP.NET核心
EN

Stack Overflow用户
提问于 2022-06-16 09:34:23
回答 2查看 86关注 0票数 0

我正在(尝试)将ASP.NET核心应用程序从.NET CoreApp3.1升级到.NET 6,但是有一次测试失败了,无法对问题结果进行反序列化。失败的原因是在.NET 6中,内容类型是application/problem+json,而在.NET核心应用程序3.1 application/xml中。

已经在迁移文档中搜索了与此有关的任何注释,但是什么都找不到。

在我的GitHub中有一个repro,控制器非常简单

代码语言:javascript
运行
复制
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();
        }
    }
}

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-11-28 21:41:33

要获得一个XML响应--匹配您的assert语句--您需要添加一个带有值application/xmlAccept HTTP报头。

来自文档

当客户端指定Accept标头时,内容协商就会发生。ASP.NET Core使用的默认格式是JSON

代码语言:javascript
运行
复制
var content = new StringContent(xml, Encoding.UTF8, MediaTypeNames.Application.Xml);
client.DefaultRequestHeaders.Add(
    "Accept", "application/xml"
    );
var response = await client.PostAsync("xml", content);

Acceptapplication/xml都有内置字符串。

代码语言:javascript
运行
复制
client.DefaultRequestHeaders.Add(
    Microsoft.Net.Http.Headers.HeaderNames.Accept,  
    System.Net.Mime.MediaTypeNames.Application.Xml
    );

将标头设置为DefaultRequestHeaders使其与该HttpClient实例发出的每个请求一起发送。

如果您只需要一个请求/只需要它,那么使用一个HttpRequestMessage实例。

代码语言:javascript
运行
复制
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变量都将包含类似于下面的有效负载。

代码语言:javascript
运行
复制
<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>
票数 1
EN

Stack Overflow用户

发布于 2022-11-29 13:52:44

TLDR

若要修复此问题,请更改注册XmlOutput格式化程序的顺序。把它调到第一位置。在启动services.AddControllers().AddXmlSerializerFormatters()之后,将XmlFormatter设置为第一个位置。还没有尝试过这段代码,但是这样的代码应该可以工作:

代码语言:javascript
运行
复制
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响应的对象结果似乎是一个问题。因此,这就是我在反编译和检查源代码时看到的情况:

  1. 请求将启动,并且由于我们有带application/xml的Produces属性,所以结果的内容类型仅为application.xml。
  2. 当检测到ObjectResult的返回类型时,ProblemDetails将被追加到内容类型列表的末尾:https://github.com/dotnet/dotnet/blob/b8bc661a7429baa89070f3bee636b7fbc1309489/src/aspnetcore/src/Mvc/Mvc.Core/src/Infrastructure/ObjectResultExecutor.cs#L152
  3. 现在,我们有了3种可能的响应内容类型。输出格式选择器现在选择错误的格式化程序:https://github.com/dotnet/dotnet/blob/b8bc661a7429baa89070f3bee636b7fbc1309489/src/aspnetcore/src/Mvc/Mvc.Core/src/Infrastructure/DefaultOutputFormatterSelector.cs#L192

结论

produces属性应该覆盖它,但是它没有覆盖它。dotnet中的当前实现给出了输出格式化程序注册的顺序,具有更高的优先级。

可能是应该以不同的方式执行DefaultOutputformatter实现,并将对象结果的内容类型作为响应类型的顺序来使用,而不是如何注册输出处理程序。不确定副作用可能是什么,但这可能是dotnet团队需要研究的问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72643642

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档