[Fixes 7139] Add format filter mapping for xml formatters
This commit is contained in:
parent
00c6b53b06
commit
2aae8774f6
|
|
@ -80,7 +80,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Json.Internal
|
||||||
options,
|
options,
|
||||||
_jsonOptions));
|
_jsonOptions));
|
||||||
|
|
||||||
options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValue.Parse("application/json"));
|
options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValues.ApplicationJson);
|
||||||
|
|
||||||
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(IJsonPatchDocument)));
|
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(IJsonPatchDocument)));
|
||||||
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(JToken)));
|
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(JToken)));
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -42,6 +43,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||||
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter(_loggerFactory));
|
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter(_loggerFactory));
|
||||||
options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(options));
|
options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(options));
|
||||||
|
|
||||||
|
// Do not override any user mapping
|
||||||
|
var key = "xml";
|
||||||
|
var mapping = options.FormatterMappings.GetMediaTypeMappingForFormat(key);
|
||||||
|
if (string.IsNullOrEmpty(mapping))
|
||||||
|
{
|
||||||
|
options.FormatterMappings.SetMediaTypeMappingForFormat(
|
||||||
|
key,
|
||||||
|
MediaTypeHeaderValues.ApplicationXml);
|
||||||
|
}
|
||||||
|
|
||||||
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider("System.Xml.Linq.XObject"));
|
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider("System.Xml.Linq.XObject"));
|
||||||
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider("System.Xml.XmlNode"));
|
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider("System.Xml.XmlNode"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -35,6 +36,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||||
/// <param name="options">The <see cref="MvcOptions"/>.</param>
|
/// <param name="options">The <see cref="MvcOptions"/>.</param>
|
||||||
public void Configure(MvcOptions options)
|
public void Configure(MvcOptions options)
|
||||||
{
|
{
|
||||||
|
// Do not override any user mapping
|
||||||
|
var key = "xml";
|
||||||
|
var mapping = options.FormatterMappings.GetMediaTypeMappingForFormat(key);
|
||||||
|
if (string.IsNullOrEmpty(mapping))
|
||||||
|
{
|
||||||
|
options.FormatterMappings.SetMediaTypeMappingForFormat(
|
||||||
|
key,
|
||||||
|
MediaTypeHeaderValues.ApplicationXml);
|
||||||
|
}
|
||||||
|
|
||||||
options.OutputFormatters.Add(new XmlSerializerOutputFormatter(_loggerFactory));
|
options.OutputFormatters.Add(new XmlSerializerOutputFormatter(_loggerFactory));
|
||||||
options.InputFormatters.Add(new XmlSerializerInputFormatter(options));
|
options.InputFormatters.Add(new XmlSerializerInputFormatter(options));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||||
|
{
|
||||||
|
public class MvcXmlDataContractSerializerMvcOptionsSetupTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void AddsFormatterMapping()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var optionsSetup = new MvcXmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
|
var options = new MvcOptions();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
optionsSetup.Configure(options);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||||
|
Assert.Equal("application/xml", mappedContentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DoesNotOverrideExistingMapping()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var optionsSetup = new MvcXmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
|
var options = new MvcOptions();
|
||||||
|
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
optionsSetup.Configure(options);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||||
|
Assert.Equal("text/xml", mappedContentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||||
|
{
|
||||||
|
public class MvcXmlSerializerMvcOptionsSetupTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void AddsFormatterMapping()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var optionsSetup = new MvcXmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
|
var options = new MvcOptions();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
optionsSetup.Configure(options);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||||
|
Assert.Equal("application/xml", mappedContentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DoesNotOverrideExistingMapping()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var optionsSetup = new MvcXmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
|
var options = new MvcOptions();
|
||||||
|
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
optionsSetup.Configure(options);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||||
|
Assert.Equal("text/xml", mappedContentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -450,13 +450,12 @@ END:VCARD
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ProducesAttribute_And_FormatFilterAttribute_Conflicting()
|
public async Task ProducesAttribute_And_FormatFilterAttribute_Conflicting()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange & Act
|
||||||
var expectedContentType = MediaTypeHeaderValue.Parse("application/json");
|
var response = await Client.GetAsync(
|
||||||
|
"http://localhost/FormatFilter/ProducesTakesPrecedenceOverUserSuppliedFormatMethod?format=json");
|
||||||
// Act
|
|
||||||
var response = await Client.GetAsync("http://localhost/FormatFilter/MethodWithFormatFilter.json");
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
// Explicit content type set by the developer takes precedence over the format requested by the end user
|
||||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -464,7 +463,8 @@ END:VCARD
|
||||||
public async Task ProducesAttribute_And_FormatFilterAttribute_Collaborating()
|
public async Task ProducesAttribute_And_FormatFilterAttribute_Collaborating()
|
||||||
{
|
{
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var response = await Client.GetAsync("http://localhost/FormatFilter/MethodWithFormatFilter");
|
var response = await Client.GetAsync(
|
||||||
|
"http://localhost/FormatFilter/ProducesTakesPrecedenceOverUserSuppliedFormatMethod");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
@ -508,5 +508,24 @@ END:VCARD
|
||||||
var contact = xmlDeserializer.ReadObject(bodyStream) as Contact;
|
var contact = xmlDeserializer.ReadObject(bodyStream) as Contact;
|
||||||
Assert.Equal("Jason Ecsemelle", contact.Name);
|
Assert.Equal("Jason Ecsemelle", contact.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task FormatFilter_XmlAsFormat_ReturnsXml()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedBody = "<FormatFilterController.Customer xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||||||
|
+ " xmlns=\"http://schemas.datacontract.org/2004/07/BasicWebSite.Controllers.ContentNegotiation\">"
|
||||||
|
+ "<Name>John</Name></FormatFilterController.Customer>";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.GetAsync(
|
||||||
|
"http://localhost/FormatFilter/CustomerInfo?format=xml");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("application/xml; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||||
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal(expectedBody, body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,24 +7,39 @@ using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
||||||
namespace BasicWebSite.Controllers.ContentNegotiation
|
namespace BasicWebSite.Controllers.ContentNegotiation
|
||||||
{
|
{
|
||||||
[Produces("application/FormatFilterController")]
|
|
||||||
public class FormatFilterController : Controller
|
public class FormatFilterController : Controller
|
||||||
{
|
{
|
||||||
public override void OnActionExecuted(ActionExecutedContext context)
|
[Produces("application/FormatFilterController")]
|
||||||
{
|
|
||||||
var result = context.Result as ObjectResult;
|
|
||||||
if (result != null)
|
|
||||||
{
|
|
||||||
result.Formatters.Add(new CustomFormatter("application/FormatFilterController"));
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnActionExecuted(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
[FormatFilter]
|
[FormatFilter]
|
||||||
public string MethodWithFormatFilter()
|
[CustomFormatterActionFilter]
|
||||||
|
public string ProducesTakesPrecedenceOverUserSuppliedFormatMethod()
|
||||||
{
|
{
|
||||||
return "MethodWithFormatFilter";
|
return "MethodWithFormatFilter";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[FormatFilter]
|
||||||
|
public Customer CustomerInfo()
|
||||||
|
{
|
||||||
|
return new Customer() { Name = "John" };
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CustomFormatterActionFilter : ActionFilterAttribute
|
||||||
|
{
|
||||||
|
public override void OnActionExecuted(ActionExecutedContext context)
|
||||||
|
{
|
||||||
|
var result = context.Result as ObjectResult;
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
result.Formatters.Add(new CustomFormatter("application/FormatFilterController"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Customer
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue