Use casing for ProblemDetails that specified by RFC

* Use JsonProperty.MemberName to specify lowercase casing for ProblemDetails properties -
  https://tools.ietf.org/html/rfc7807#section-3
* Use XML NS and lowercase for Xml elements specified by RFC -
  https://tools.ietf.org/html/rfc7807#appendix-A

Fixes https://github.com/aspnet/Mvc/issues/8501
This commit is contained in:
Pranav K 2018-10-01 15:05:56 -07:00
parent d3c8d171bd
commit 164d14064c
8 changed files with 104 additions and 74 deletions

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc
/// (e.g., using HTML [W3C.REC-html5-20141028]). When this member is not present, its value is assumed to be /// (e.g., using HTML [W3C.REC-html5-20141028]). When this member is not present, its value is assumed to be
/// "about:blank". /// "about:blank".
/// </summary> /// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "type")]
public string Type { get; set; } public string Type { get; set; }
/// <summary> /// <summary>
@ -26,25 +26,25 @@ namespace Microsoft.AspNetCore.Mvc
/// of the problem, except for purposes of localization(e.g., using proactive content negotiation; /// of the problem, except for purposes of localization(e.g., using proactive content negotiation;
/// see[RFC7231], Section 3.4). /// see[RFC7231], Section 3.4).
/// </summary> /// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "title")]
public string Title { get; set; } public string Title { get; set; }
/// <summary> /// <summary>
/// The HTTP status code([RFC7231], Section 6) generated by the origin server for this occurrence of the problem. /// The HTTP status code([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.
/// </summary> /// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "status")]
public int? Status { get; set; } public int? Status { get; set; }
/// <summary> /// <summary>
/// A human-readable explanation specific to this occurrence of the problem. /// A human-readable explanation specific to this occurrence of the problem.
/// </summary> /// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "detail")]
public string Detail { get; set; } public string Detail { get; set; }
/// <summary> /// <summary>
/// A URI reference that identifies the specific occurrence of the problem.It may or may not yield further information if dereferenced. /// A URI reference that identifies the specific occurrence of the problem.It may or may not yield further information if dereferenced.
/// </summary> /// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] [JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "instance")]
public string Instance { get; set; } public string Instance { get; set; }
/// <summary> /// <summary>

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Core; using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
{ {
@ -64,6 +65,7 @@ namespace Microsoft.AspNetCore.Mvc
/// <summary> /// <summary>
/// Gets or sets the validation errors associated with this instance of <see cref="ValidationProblemDetails"/>. /// Gets or sets the validation errors associated with this instance of <see cref="ValidationProblemDetails"/>.
/// </summary> /// </summary>
[JsonProperty(PropertyName = "errors")]
public IDictionary<string, string[]> Errors { get; } = new Dictionary<string, string[]>(StringComparer.Ordinal); public IDictionary<string, string[]> Errors { get; } = new Dictionary<string, string[]>(StringComparer.Ordinal);
} }
} }

View File

@ -12,9 +12,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
/// <summary> /// <summary>
/// Wrapper class for <see cref="Mvc.ProblemDetails"/> to enable it to be serialized by the xml formatters. /// Wrapper class for <see cref="Mvc.ProblemDetails"/> to enable it to be serialized by the xml formatters.
/// </summary> /// </summary>
[XmlRoot(nameof(ProblemDetails))] [XmlRoot("problem", Namespace = Namespace)]
public class ProblemDetailsWrapper : IXmlSerializable, IUnwrappable public class ProblemDetailsWrapper : IXmlSerializable, IUnwrappable
{ {
internal const string Namespace = "urn:ietf:rfc:7807";
/// <summary> /// <summary>
/// Key used to represent dictionary elements with empty keys /// Key used to represent dictionary elements with empty keys
/// </summary> /// </summary>
@ -83,25 +85,25 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
switch (name) switch (name)
{ {
case nameof(ProblemDetails.Detail): case "detail":
ProblemDetails.Detail = value; ProblemDetails.Detail = value;
break; break;
case nameof(ProblemDetails.Instance): case "instance":
ProblemDetails.Instance = value; ProblemDetails.Instance = value;
break; break;
case nameof(ProblemDetails.Status): case "status":
ProblemDetails.Status = string.IsNullOrEmpty(value) ? ProblemDetails.Status = string.IsNullOrEmpty(value) ?
(int?)null : (int?)null :
int.Parse(value, CultureInfo.InvariantCulture); int.Parse(value, CultureInfo.InvariantCulture);
break; break;
case nameof(ProblemDetails.Title): case "title":
ProblemDetails.Title = value; ProblemDetails.Title = value;
break; break;
case nameof(ProblemDetails.Type): case "type":
ProblemDetails.Type = value; ProblemDetails.Type = value;
break; break;
@ -122,20 +124,20 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
if (!string.IsNullOrEmpty(ProblemDetails.Detail)) if (!string.IsNullOrEmpty(ProblemDetails.Detail))
{ {
writer.WriteElementString( writer.WriteElementString(
XmlConvert.EncodeLocalName(nameof(ProblemDetails.Detail)), XmlConvert.EncodeLocalName("detail"),
ProblemDetails.Detail); ProblemDetails.Detail);
} }
if (!string.IsNullOrEmpty(ProblemDetails.Instance)) if (!string.IsNullOrEmpty(ProblemDetails.Instance))
{ {
writer.WriteElementString( writer.WriteElementString(
XmlConvert.EncodeLocalName(nameof(ProblemDetails.Instance)), XmlConvert.EncodeLocalName("instance"),
ProblemDetails.Instance); ProblemDetails.Instance);
} }
if (ProblemDetails.Status.HasValue) if (ProblemDetails.Status.HasValue)
{ {
writer.WriteStartElement(XmlConvert.EncodeLocalName(nameof(ProblemDetails.Status))); writer.WriteStartElement(XmlConvert.EncodeLocalName("status"));
writer.WriteValue(ProblemDetails.Status.Value); writer.WriteValue(ProblemDetails.Status.Value);
writer.WriteEndElement(); writer.WriteEndElement();
} }
@ -143,14 +145,14 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
if (!string.IsNullOrEmpty(ProblemDetails.Title)) if (!string.IsNullOrEmpty(ProblemDetails.Title))
{ {
writer.WriteElementString( writer.WriteElementString(
XmlConvert.EncodeLocalName(nameof(ProblemDetails.Title)), XmlConvert.EncodeLocalName("title"),
ProblemDetails.Title); ProblemDetails.Title);
} }
if (!string.IsNullOrEmpty(ProblemDetails.Type)) if (!string.IsNullOrEmpty(ProblemDetails.Type))
{ {
writer.WriteElementString( writer.WriteElementString(
XmlConvert.EncodeLocalName(nameof(ProblemDetails.Type)), XmlConvert.EncodeLocalName("type"),
ProblemDetails.Type); ProblemDetails.Type);
} }

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
/// <summary> /// <summary>
/// Wrapper class for <see cref="ValidationProblemDetails"/> to enable it to be serialized by the xml formatters. /// Wrapper class for <see cref="ValidationProblemDetails"/> to enable it to be serialized by the xml formatters.
/// </summary> /// </summary>
[XmlRoot(nameof(ValidationProblemDetails))] [XmlRoot("problem", Namespace = "urn:ietf:rfc:7807")]
public class ValidationProblemDetailsWrapper : ProblemDetailsWrapper, IUnwrappable public class ValidationProblemDetailsWrapper : ProblemDetailsWrapper, IUnwrappable
{ {
private static readonly string ErrorKey = "MVC-Errors"; private static readonly string ErrorKey = "MVC-Errors";

View File

@ -17,14 +17,14 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
{ {
// Arrange // Arrange
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ProblemDetails>" + "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Title>Some title</Title>" + "<title>Some title</title>" +
"<Status>403</Status>" + "<status>403</status>" +
"<Instance>Some instance</Instance>" + "<instance>Some instance</instance>" +
"<key1>Test Value 1</key1>" + "<key1>Test Value 1</key1>" +
"<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" + "<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" +
"<MVC-Empty>Test Value 3</MVC-Empty>" + "<MVC-Empty>Test Value 3</MVC-Empty>" +
"</ProblemDetails>"; "</problem>";
var serializer = new DataContractSerializer(typeof(ProblemDetailsWrapper)); var serializer = new DataContractSerializer(typeof(ProblemDetailsWrapper));
// Act // Act
@ -76,13 +76,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
var wrapper = new ProblemDetailsWrapper(problemDetails); var wrapper = new ProblemDetailsWrapper(problemDetails);
var outputStream = new MemoryStream(); var outputStream = new MemoryStream();
var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ProblemDetails>" + "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Detail>Some detail</Detail>" + "<detail>Some detail</detail>" +
"<Title>Some title</Title>" + "<title>Some title</title>" +
"<key1>Test Value 1</key1>" + "<key1>Test Value 1</key1>" +
"<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" + "<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" +
"<MVC-Empty>Test Value 3</MVC-Empty>" + "<MVC-Empty>Test Value 3</MVC-Empty>" +
"</ProblemDetails>"; "</problem>";
// Act // Act
using (var xmlWriter = XmlWriter.Create(outputStream)) using (var xmlWriter = XmlWriter.Create(outputStream))

View File

@ -17,10 +17,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
{ {
// Arrange // Arrange
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ValidationProblemDetails>" + "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Title>Some title</Title>" + "<title>Some title</title>" +
"<Status>400</Status>" + "<status>400</status>" +
"<Instance>Some instance</Instance>" + "<instance>Some instance</instance>" +
"<key1>Test Value 1</key1>" + "<key1>Test Value 1</key1>" +
"<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" + "<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" +
"<MVC-Errors>" + "<MVC-Errors>" +
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
"<_x005B_error2_x005D_>Test error 3</_x005B_error2_x005D_>" + "<_x005B_error2_x005D_>Test error 3</_x005B_error2_x005D_>" +
"<MVC-Empty>Test error 4</MVC-Empty>" + "<MVC-Empty>Test error 4</MVC-Empty>" +
"</MVC-Errors>" + "</MVC-Errors>" +
"</ValidationProblemDetails>"; "</problem>";
var serializer = new DataContractSerializer(typeof(ValidationProblemDetailsWrapper)); var serializer = new DataContractSerializer(typeof(ValidationProblemDetailsWrapper));
// Act // Act
@ -78,13 +78,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
{ {
// Arrange // Arrange
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ValidationProblemDetails>" + "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Title>Some title</Title>" + "<title>Some title</title>" +
"<Status>400</Status>" + "<status>400</status>" +
"<Instance>Some instance</Instance>" + "<instance>Some instance</instance>" +
"<key1>Test Value 1</key1>" + "<key1>Test Value 1</key1>" +
"<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" + "<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" +
"</ValidationProblemDetails>"; "</problem>";
var serializer = new DataContractSerializer(typeof(ValidationProblemDetailsWrapper)); var serializer = new DataContractSerializer(typeof(ValidationProblemDetailsWrapper));
// Act // Act
@ -118,11 +118,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
{ {
// Arrange // Arrange
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ValidationProblemDetails>" + "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Title>Some title</Title>" + "<title>Some title</title>" +
"<Status>400</Status>" + "<status>400</status>" +
"<MVC-Errors />" + "<MVC-Errors />" +
"</ValidationProblemDetails>"; "</problem>";
var serializer = new DataContractSerializer(typeof(ValidationProblemDetailsWrapper)); var serializer = new DataContractSerializer(typeof(ValidationProblemDetailsWrapper));
// Act // Act
@ -160,9 +160,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
var wrapper = new ValidationProblemDetailsWrapper(problemDetails); var wrapper = new ValidationProblemDetailsWrapper(problemDetails);
var outputStream = new MemoryStream(); var outputStream = new MemoryStream();
var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ValidationProblemDetails>" + "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Detail>Some detail</Detail>" + "<detail>Some detail</detail>" +
"<Title>Some title</Title>" + "<title>Some title</title>" +
"<key1>Test Value 1</key1>" + "<key1>Test Value 1</key1>" +
"<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" + "<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" +
"<MVC-Errors>" + "<MVC-Errors>" +
@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
"<_x005B_error2_x005D_>Test error 3</_x005B_error2_x005D_>" + "<_x005B_error2_x005D_>Test error 3</_x005B_error2_x005D_>" +
"<MVC-Empty>Test error 4</MVC-Empty>" + "<MVC-Empty>Test error 4</MVC-Empty>" +
"</MVC-Errors>" + "</MVC-Errors>" +
"</ValidationProblemDetails>"; "</problem>";
// Act // Act
using (var xmlWriter = XmlWriter.Create(outputStream)) using (var xmlWriter = XmlWriter.Create(outputStream))
@ -203,12 +203,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
var wrapper = new ValidationProblemDetailsWrapper(problemDetails); var wrapper = new ValidationProblemDetailsWrapper(problemDetails);
var outputStream = new MemoryStream(); var outputStream = new MemoryStream();
var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<ValidationProblemDetails>" + "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Detail>Some detail</Detail>" + "<detail>Some detail</detail>" +
"<Title>Some title</Title>" + "<title>Some title</title>" +
"<key1>Test Value 1</key1>" + "<key1>Test Value 1</key1>" +
"<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" + "<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" +
"</ValidationProblemDetails>"; "</problem>";
// Act // Act
using (var xmlWriter = XmlWriter.Create(outputStream)) using (var xmlWriter = XmlWriter.Create(outputStream))

View File

@ -216,12 +216,12 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Arrange // Arrange
using (new ActivityReplacer()) using (new ActivityReplacer())
{ {
var expected = "<ProblemDetails>" + var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Status>404</Status>" + "<status>404</status>" +
"<Title>Not Found</Title>" + "<title>Not Found</title>" +
"<Type>https://tools.ietf.org/html/rfc7231#section-6.5.4</Type>" + "<type>https://tools.ietf.org/html/rfc7231#section-6.5.4</type>" +
$"<traceId>{Activity.Current.Id}</traceId>" + $"<traceId>{Activity.Current.Id}</traceId>" +
"</ProblemDetails>"; "</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningClientErrorStatusCodeResult"); var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningClientErrorStatusCodeResult");
@ -237,8 +237,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task ProblemDetails_WithExtensionMembers_IsSerialized() public async Task ProblemDetails_WithExtensionMembers_IsSerialized()
{ {
// Arrange // Arrange
var expected = @"<ProblemDetails><Instance>instance</Instance><Status>404</Status><Title>title</Title> var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
<Correlation>correlation</Correlation><Accounts>Account1 Account2</Accounts></ProblemDetails>"; "<instance>instance</instance>" +
"<status>404</status>" +
"<title>title</title>" +
"<Correlation>correlation</Correlation>" +
"<Accounts>Account1 Account2</Accounts>" +
"</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningProblemDetails"); var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningProblemDetails");
@ -255,14 +260,14 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Arrange // Arrange
using (new ActivityReplacer()) using (new ActivityReplacer())
{ {
var expected = "<ValidationProblemDetails>" + var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Status>400</Status>" + "<status>400</status>" +
"<Title>One or more validation errors occurred.</Title>" + "<title>One or more validation errors occurred.</title>" +
$"<traceId>{Activity.Current.Id}</traceId>" + $"<traceId>{Activity.Current.Id}</traceId>" +
"<MVC-Errors>" + "<MVC-Errors>" +
"<State>The State field is required.</State>" + "<State>The State field is required.</State>" +
"</MVC-Errors>" + "</MVC-Errors>" +
"</ValidationProblemDetails>"; "</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningValidationProblem"); var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningValidationProblem");
@ -278,8 +283,16 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task ValidationProblemDetails_WithExtensionMembers_IsSerialized() public async Task ValidationProblemDetails_WithExtensionMembers_IsSerialized()
{ {
// Arrange // Arrange
var expected = @"<ValidationProblemDetails><Detail>some detail</Detail><Status>400</Status><Title>One or more validation errors occurred.</Title> var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
<Type>some type</Type><CorrelationId>correlation</CorrelationId><MVC-Errors><Error1>ErrorValue</Error1></MVC-Errors></ValidationProblemDetails>"; "<detail>some detail</detail>" +
"<status>400</status>" +
"<title>One or more validation errors occurred.</title>" +
"<type>some type</type>" +
"<CorrelationId>correlation</CorrelationId>" +
"<MVC-Errors>" +
"<Error1>ErrorValue</Error1>" +
"</MVC-Errors>" +
"</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningValidationDetailsWithMetadata"); var response = await Client.GetAsync("/api/XmlDataContractApi/ActionReturningValidationDetailsWithMetadata");

View File

@ -191,12 +191,12 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Arrange // Arrange
using (new ActivityReplacer()) using (new ActivityReplacer())
{ {
var expected = "<ProblemDetails>" + var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Status>404</Status>" + "<status>404</status>" +
"<Title>Not Found</Title>" + "<title>Not Found</title>" +
"<Type>https://tools.ietf.org/html/rfc7231#section-6.5.4</Type>" + "<type>https://tools.ietf.org/html/rfc7231#section-6.5.4</type>" +
$"<traceId>{Activity.Current.Id}</traceId>" + $"<traceId>{Activity.Current.Id}</traceId>" +
"</ProblemDetails>"; "</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningClientErrorStatusCodeResult"); var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningClientErrorStatusCodeResult");
@ -212,8 +212,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task ProblemDetails_WithExtensionMembers_IsSerialized() public async Task ProblemDetails_WithExtensionMembers_IsSerialized()
{ {
// Arrange // Arrange
var expected = @"<ProblemDetails><Instance>instance</Instance><Status>404</Status><Title>title</Title> var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
<Correlation>correlation</Correlation><Accounts>Account1 Account2</Accounts></ProblemDetails>"; "<instance>instance</instance>" +
"<status>404</status>" +
"<title>title</title>" +
"<Correlation>correlation</Correlation>" +
"<Accounts>Account1 Account2</Accounts>" +
"</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningProblemDetails"); var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningProblemDetails");
@ -230,14 +235,14 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
// Arrange // Arrange
using (new ActivityReplacer()) using (new ActivityReplacer())
{ {
var expected = "<ValidationProblemDetails>" + var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
"<Status>400</Status>" + "<status>400</status>" +
"<Title>One or more validation errors occurred.</Title>" + "<title>One or more validation errors occurred.</title>" +
$"<traceId>{Activity.Current.Id}</traceId>" + $"<traceId>{Activity.Current.Id}</traceId>" +
"<MVC-Errors>" + "<MVC-Errors>" +
"<State>The State field is required.</State>" + "<State>The State field is required.</State>" +
"</MVC-Errors>" + "</MVC-Errors>" +
"</ValidationProblemDetails>"; "</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningValidationProblem"); var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningValidationProblem");
@ -253,8 +258,16 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
public async Task ValidationProblemDetails_WithExtensionMembers_IsSerialized() public async Task ValidationProblemDetails_WithExtensionMembers_IsSerialized()
{ {
// Arrange // Arrange
var expected = @"<ValidationProblemDetails><Detail>some detail</Detail><Status>400</Status><Title>One or more validation errors occurred.</Title> var expected = "<problem xmlns=\"urn:ietf:rfc:7807\">" +
<Type>some type</Type><CorrelationId>correlation</CorrelationId><MVC-Errors><Error1>ErrorValue</Error1></MVC-Errors></ValidationProblemDetails>"; "<detail>some detail</detail>" +
"<status>400</status>" +
"<title>One or more validation errors occurred.</title>" +
"<type>some type</type>" +
"<CorrelationId>correlation</CorrelationId>" +
"<MVC-Errors>" +
"<Error1>ErrorValue</Error1>" +
"</MVC-Errors>" +
"</problem>";
// Act // Act
var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningValidationDetailsWithMetadata"); var response = await Client.GetAsync("/api/XmlSerializerApi/ActionReturningValidationDetailsWithMetadata");