[Fixes #1791]Remove XML formatter from defaults
This commit is contained in:
parent
9aff289dfe
commit
02f4ca9f05
|
|
@ -50,6 +50,8 @@ namespace MvcSample.Web
|
|||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(PassThroughAttribute), order: 17);
|
||||
|
||||
options.AddXmlDataContractSerializerFormatter();
|
||||
});
|
||||
services.Configure<RazorViewEngineOptions>(options =>
|
||||
{
|
||||
|
|
@ -90,6 +92,7 @@ namespace MvcSample.Web
|
|||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(PassThroughAttribute), order: 17);
|
||||
options.AddXmlDataContractSerializerFormatter();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,15 @@ namespace TagHelperSample.Web
|
|||
app.UseServices(services =>
|
||||
{
|
||||
services.AddMvc();
|
||||
|
||||
|
||||
// Setup services with a test AssemblyProvider so that only the sample's assemblies are loaded. This
|
||||
// prevents loading controllers from other assemblies when the sample is used in functional tests.
|
||||
services.AddTransient<IAssemblyProvider, TestAssemblyProvider<Startup>>();
|
||||
|
||||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
options.AddXmlDataContractSerializerFormatter();
|
||||
});
|
||||
});
|
||||
app.UseMvc();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,4 +15,9 @@
|
|||
<DevelopmentServerPort>30540</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties project_1json__JSONSchema="http://www.asp.net/media/4878834/project.json" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
@ -63,20 +64,43 @@ namespace Microsoft.AspNet.Mvc
|
|||
public virtual IOutputFormatter SelectFormatter(OutputFormatterContext formatterContext,
|
||||
IEnumerable<IOutputFormatter> formatters)
|
||||
{
|
||||
var incomingAcceptHeader = formatterContext.ActionContext.HttpContext.Request.GetTypedHeaders().Accept;
|
||||
var sortedAcceptHeaders = SortMediaTypeHeaderValues(incomingAcceptHeader)
|
||||
.Where(header => header.Quality != HeaderQuality.NoMatch)
|
||||
.ToArray();
|
||||
var incomingAcceptHeaderMediaTypes = formatterContext.ActionContext.HttpContext.Request.GetTypedHeaders().Accept ??
|
||||
new MediaTypeHeaderValue[] { };
|
||||
|
||||
// By default we want to ignore considering accept headers for content negotiation when
|
||||
// they have a media type like */* in them. Browsers typically have these media types.
|
||||
// In these cases we would want the first formatter in the list of output formatters to
|
||||
// write the response. This default behavior can be changed through options, so checking here.
|
||||
var options = formatterContext.ActionContext.HttpContext
|
||||
.RequestServices
|
||||
.GetRequiredService<IOptions<MvcOptions>>()
|
||||
.Options;
|
||||
|
||||
var respectAcceptHeader = true;
|
||||
if (options.RespectBrowserAcceptHeader == false
|
||||
&& incomingAcceptHeaderMediaTypes.Any(mediaType => mediaType.MatchesAllTypes))
|
||||
{
|
||||
respectAcceptHeader = false;
|
||||
}
|
||||
|
||||
IEnumerable<MediaTypeHeaderValue> sortedAcceptHeaderMediaTypes = null;
|
||||
if (respectAcceptHeader)
|
||||
{
|
||||
sortedAcceptHeaderMediaTypes = SortMediaTypeHeaderValues(incomingAcceptHeaderMediaTypes)
|
||||
.Where(header => header.Quality != HeaderQuality.NoMatch);
|
||||
}
|
||||
|
||||
IOutputFormatter selectedFormatter = null;
|
||||
|
||||
if (ContentTypes == null || ContentTypes.Count == 0)
|
||||
{
|
||||
// Select based on sorted accept headers.
|
||||
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
|
||||
formatterContext,
|
||||
formatters,
|
||||
sortedAcceptHeaders);
|
||||
if (respectAcceptHeader)
|
||||
{
|
||||
// Select based on sorted accept headers.
|
||||
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
|
||||
formatterContext,
|
||||
formatters,
|
||||
sortedAcceptHeaderMediaTypes);
|
||||
}
|
||||
|
||||
if (selectedFormatter == null)
|
||||
{
|
||||
|
|
@ -124,16 +148,15 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
else
|
||||
{
|
||||
// Filter and remove accept headers which cannot support any of the user specified content types.
|
||||
var filteredAndSortedAcceptHeaders = sortedAcceptHeaders
|
||||
.Where(acceptHeader =>
|
||||
ContentTypes
|
||||
.Any(contentType =>
|
||||
contentType.IsSubsetOf(acceptHeader)))
|
||||
.ToArray();
|
||||
|
||||
if (filteredAndSortedAcceptHeaders.Length > 0)
|
||||
if (respectAcceptHeader)
|
||||
{
|
||||
// Filter and remove accept headers which cannot support any of the user specified content types.
|
||||
var filteredAndSortedAcceptHeaders = sortedAcceptHeaderMediaTypes
|
||||
.Where(acceptHeader =>
|
||||
ContentTypes
|
||||
.Any(contentType =>
|
||||
contentType.IsSubsetOf(acceptHeader)));
|
||||
|
||||
selectedFormatter = SelectFormatterUsingSortedAcceptHeaders(
|
||||
formatterContext,
|
||||
formatters,
|
||||
|
|
@ -194,20 +217,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
return selectedFormatter;
|
||||
}
|
||||
|
||||
private static MediaTypeHeaderValue[] SortMediaTypeHeaderValues
|
||||
(IEnumerable<MediaTypeHeaderValue> headerValues)
|
||||
private static IEnumerable<MediaTypeHeaderValue> SortMediaTypeHeaderValues(
|
||||
IEnumerable<MediaTypeHeaderValue> headerValues)
|
||||
{
|
||||
if (headerValues == null)
|
||||
{
|
||||
return new MediaTypeHeaderValue[] { };
|
||||
}
|
||||
|
||||
// Use OrderBy() instead of Array.Sort() as it performs fewer comparisons. In this case the comparisons
|
||||
// are quite expensive so OrderBy() performs better.
|
||||
return headerValues.OrderByDescending(headerValue =>
|
||||
headerValue,
|
||||
MediaTypeHeaderValueComparer.QualityComparer)
|
||||
.ToArray();
|
||||
MediaTypeHeaderValueComparer.QualityComparer);
|
||||
}
|
||||
|
||||
private IEnumerable<IOutputFormatter> GetDefaultFormatters(ActionContext context)
|
||||
|
|
|
|||
|
|
@ -125,5 +125,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// the <see cref="ApplicationModel"/> when discovering actions.
|
||||
/// </summary>
|
||||
public List<IApplicationModelConvention> ApplicationModelConventions { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flag which causes content negotiation to ignore Accept header
|
||||
/// when it contains the media type */*. <see langword="false"/> by default.
|
||||
/// </summary>
|
||||
public bool RespectBrowserAcceptHeader { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public static class MvcOptionsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds <see cref="XmlDataContractSerializerInputFormatter"/> and
|
||||
/// <see cref="XmlDataContractSerializerOutputFormatter"/> to the input and output formatter
|
||||
/// collections respectively.
|
||||
/// </summary>
|
||||
/// <param name="options">The MvcOptions</param>
|
||||
public static void AddXmlDataContractSerializerFormatter([NotNull] this MvcOptions options)
|
||||
{
|
||||
options.OutputFormatters.Add(
|
||||
new XmlDataContractSerializerOutputFormatter(XmlOutputFormatter.GetDefaultXmlWriterSettings()));
|
||||
|
||||
options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,12 +44,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
options.OutputFormatters.Add(new HttpNoContentOutputFormatter());
|
||||
options.OutputFormatters.Add(new TextPlainFormatter());
|
||||
options.OutputFormatters.Add(new JsonOutputFormatter());
|
||||
options.OutputFormatters.Add(
|
||||
new XmlDataContractSerializerOutputFormatter(XmlOutputFormatter.GetDefaultXmlWriterSettings()));
|
||||
|
||||
// Set up default input formatters.
|
||||
options.InputFormatters.Add(new JsonInputFormatter());
|
||||
options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
|
||||
|
||||
// Set up ValueProviders
|
||||
options.ValueProviderFactories.Add(new RouteValueValueProviderFactory());
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Http.Core;
|
|||
using Microsoft.AspNet.Http.Core.Collections;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -92,6 +93,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
var services = new Mock<IServiceProvider>();
|
||||
services.Setup(p => p.GetService(typeof(IOutputFormattersProvider))).Returns(new TestOutputFormatterProvider());
|
||||
httpContext.RequestServices = services.Object;
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
services.Setup(p => p.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Microsoft.AspNet.Http;
|
|||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -97,6 +98,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
httpContext.Setup(o => o.Request)
|
||||
.Returns(request);
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
httpContext.Setup(o => o.Response)
|
||||
.Returns(response);
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOutputFormattersProvider)))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -69,7 +70,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
.Returns(response);
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(new TestOutputFormatterProvider());
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
return httpContext.Object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
|||
httpResponse.SetupGet(r => r.Body).Returns(stream);
|
||||
|
||||
var actionContext = CreateMockActionContext(httpResponse.Object, acceptHeader);
|
||||
|
||||
var result = new ObjectResult(input);
|
||||
|
||||
// Set the content type property explicitly.
|
||||
|
|
@ -467,10 +468,148 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
|||
Assert.Equal(tempStream.ToArray(), ((MemoryStream)actionContext.HttpContext.Response.Body).ToArray());
|
||||
}
|
||||
|
||||
private static ActionContext CreateMockActionContext(HttpResponse response = null,
|
||||
[Theory]
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"application/json; charset=utf-8")] //Chrome
|
||||
[InlineData("text/html, application/xhtml+xml, */*",
|
||||
"application/json; charset=utf-8")] //IE
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"application/json; charset=utf-8")] //Firefox
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"application/json; charset=utf-8")] //Safari
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"application/json; charset=utf-8")] //Opera
|
||||
[InlineData("*/*", @"application/json; charset=utf-8")]
|
||||
[InlineData("text/html,*/*;q=0.8,application/xml;q=0.9",
|
||||
"application/json; charset=utf-8")]
|
||||
public async Task ObjectResult_SelectDefaultFormatter_OnAllMediaRangeAcceptHeaderMediaType(
|
||||
string acceptHeader,
|
||||
string expectedResponseContentType)
|
||||
{
|
||||
// Arrange
|
||||
var objectResult = new ObjectResult(new Person() { Name = "John" });
|
||||
var outputFormatters = new IOutputFormatter[] {
|
||||
new HttpNoContentOutputFormatter(),
|
||||
new TextPlainFormatter(),
|
||||
new JsonOutputFormatter(),
|
||||
new XmlDataContractSerializerOutputFormatter(XmlSerializerOutputFormatter.GetDefaultXmlWriterSettings())
|
||||
};
|
||||
var response = GetMockHttpResponse();
|
||||
|
||||
var actionContext = CreateMockActionContext(
|
||||
outputFormatters,
|
||||
response.Object,
|
||||
requestAcceptHeader: acceptHeader);
|
||||
|
||||
// Act
|
||||
await objectResult.ExecuteResultAsync(actionContext);
|
||||
|
||||
// Assert
|
||||
response.VerifySet(resp => resp.ContentType = expectedResponseContentType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"application/xml; charset=utf-8")] //Chrome
|
||||
[InlineData("text/html, application/xhtml+xml, */*",
|
||||
"application/json; charset=utf-8")] //IE
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"application/xml; charset=utf-8")] //Firefox
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
||||
"application/xml; charset=utf-8")] //Safari
|
||||
[InlineData("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"application/xml; charset=utf-8")] //Opera
|
||||
[InlineData("*/*",
|
||||
"application/json; charset=utf-8")]
|
||||
[InlineData("text/html,*/*;q=0.8,application/xml;q=0.9",
|
||||
"application/xml; charset=utf-8")]
|
||||
public async Task ObjectResult_PerformsContentNegotiation_OnAllMediaRangeAcceptHeaderMediaType(
|
||||
string acceptHeader,
|
||||
string expectedResponseContentType)
|
||||
{
|
||||
// Arrange
|
||||
var objectResult = new ObjectResult(new Person() { Name = "John" });
|
||||
var outputFormatters = new IOutputFormatter[] {
|
||||
new HttpNoContentOutputFormatter(),
|
||||
new TextPlainFormatter(),
|
||||
new JsonOutputFormatter(),
|
||||
new XmlDataContractSerializerOutputFormatter(XmlSerializerOutputFormatter.GetDefaultXmlWriterSettings())
|
||||
};
|
||||
var response = GetMockHttpResponse();
|
||||
|
||||
var actionContext = CreateMockActionContext(
|
||||
outputFormatters,
|
||||
response.Object,
|
||||
requestAcceptHeader: acceptHeader,
|
||||
respectBrowserAcceptHeader: true);
|
||||
|
||||
// Act
|
||||
await objectResult.ExecuteResultAsync(actionContext);
|
||||
|
||||
// Assert
|
||||
response.VerifySet(resp => resp.ContentType = expectedResponseContentType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/xml;q=0.9,text/plain;q=0.5", "application/xml; charset=utf-8", false)]
|
||||
[InlineData("application/xml;q=0.9,*/*;q=0.5", "application/json; charset=utf-8", false)]
|
||||
[InlineData("application/xml;q=0.9,text/plain;q=0.5", "application/xml; charset=utf-8", true)]
|
||||
[InlineData("application/xml;q=0.9,*/*;q=0.5", "application/xml; charset=utf-8", true)]
|
||||
public async Task ObjectResult_WildcardAcceptMediaType_AndExplicitResponseContentType(
|
||||
string acceptHeader,
|
||||
string expectedResponseContentType,
|
||||
bool respectBrowserAcceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var objectResult = new ObjectResult(new Person() { Name = "John" });
|
||||
objectResult.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
|
||||
objectResult.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
|
||||
var outputFormatters = new IOutputFormatter[] {
|
||||
new HttpNoContentOutputFormatter(),
|
||||
new TextPlainFormatter(),
|
||||
new JsonOutputFormatter(),
|
||||
new XmlDataContractSerializerOutputFormatter(XmlSerializerOutputFormatter.GetDefaultXmlWriterSettings())
|
||||
};
|
||||
var response = GetMockHttpResponse();
|
||||
|
||||
var actionContext = CreateMockActionContext(
|
||||
outputFormatters,
|
||||
response.Object,
|
||||
acceptHeader,
|
||||
respectBrowserAcceptHeader: respectBrowserAcceptHeader);
|
||||
|
||||
// Act
|
||||
await objectResult.ExecuteResultAsync(actionContext);
|
||||
|
||||
// Assert
|
||||
response.VerifySet(resp => resp.ContentType = expectedResponseContentType);
|
||||
}
|
||||
|
||||
private static ActionContext CreateMockActionContext(
|
||||
HttpResponse response = null,
|
||||
string requestAcceptHeader = "application/*",
|
||||
string requestContentType = "application/json",
|
||||
string requestAcceptCharsetHeader = "")
|
||||
string requestAcceptCharsetHeader = "",
|
||||
bool respectBrowserAcceptHeader = false)
|
||||
{
|
||||
var formatters = new IOutputFormatter[] { new TextPlainFormatter(), new JsonOutputFormatter() };
|
||||
|
||||
return CreateMockActionContext(
|
||||
formatters,
|
||||
response: response,
|
||||
requestAcceptHeader: requestAcceptHeader,
|
||||
requestContentType: requestContentType,
|
||||
requestAcceptCharsetHeader: requestAcceptCharsetHeader,
|
||||
respectBrowserAcceptHeader: respectBrowserAcceptHeader);
|
||||
}
|
||||
|
||||
private static ActionContext CreateMockActionContext(
|
||||
IEnumerable<IOutputFormatter> outputFormatters,
|
||||
HttpResponse response = null,
|
||||
string requestAcceptHeader = "application/*",
|
||||
string requestContentType = "application/json",
|
||||
string requestAcceptCharsetHeader = "",
|
||||
bool respectBrowserAcceptHeader = false)
|
||||
{
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
if (response != null)
|
||||
|
|
@ -490,7 +629,17 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
|||
httpContext.Setup(o => o.Request).Returns(request);
|
||||
httpContext.Setup(o => o.RequestServices).Returns(GetServiceProvider());
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(new TestOutputFormatterProvider());
|
||||
.Returns(new TestOutputFormatterProvider(outputFormatters));
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions()
|
||||
{
|
||||
RespectBrowserAcceptHeader = respectBrowserAcceptHeader
|
||||
});
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
}
|
||||
|
||||
|
|
@ -551,17 +700,25 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
|||
|
||||
private class TestOutputFormatterProvider : IOutputFormattersProvider
|
||||
{
|
||||
private readonly IEnumerable<IOutputFormatter> _formatters;
|
||||
|
||||
public TestOutputFormatterProvider(IEnumerable<IOutputFormatter> formatters)
|
||||
{
|
||||
_formatters = formatters;
|
||||
}
|
||||
|
||||
public IReadOnlyList<IOutputFormatter> OutputFormatters
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<IOutputFormatter>()
|
||||
{
|
||||
new TextPlainFormatter(),
|
||||
new JsonOutputFormatter()
|
||||
};
|
||||
return _formatters.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Person
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -1957,6 +1958,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
.Returns(mockFormattersProvider.Object);
|
||||
httpResponse.Body = new MemoryStream();
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
var actionContext = new ActionContext(
|
||||
httpContext: httpContext.Object,
|
||||
routeData: new RouteData(),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -192,6 +193,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(mockFormattersProvider.Object);
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
// This is the ultimate fallback, it will be used if none of the formatters from options
|
||||
// work.
|
||||
if (enableFallback)
|
||||
|
|
|
|||
|
|
@ -279,11 +279,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
if (optionsAccessor == null)
|
||||
{
|
||||
var mockOptionsAccessor = new Mock<IOptions<MvcOptions>>();
|
||||
mockOptionsAccessor.SetupGet(o => o.Options)
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
|
||||
optionsAccessor = mockOptionsAccessor.Object;
|
||||
optionsAccessor = options.Object;
|
||||
}
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
public class RespectBrowserAcceptHeaderTests
|
||||
{
|
||||
private readonly IServiceProvider _provider = TestHelper.CreateServices(nameof(FormatterWebSite));
|
||||
private readonly Action<IApplicationBuilder> _app = new FormatterWebSite.Startup().Configure;
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/xml,*/*;0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_FirstFormatterInListWritesResponse(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
client.DefaultRequestHeaders.Add("Accept", acceptHeader);
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/RespectBrowserAcceptHeader/EmployeeInfo");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
var responseData = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("{\"Id\":10,\"Name\":\"John\"}", responseData);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/xml,*/*;0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_ProducesAttributeIsHonored(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
client.DefaultRequestHeaders.Add("Accept", acceptHeader);
|
||||
var expectedResponseData = "<RespectBrowserAcceptHeaderController.Employee xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"" +
|
||||
" xmlns=\"http://schemas.datacontract.org/2004/07/FormatterWebSite.Controllers\"><Id>20</Id><Name>Mike" +
|
||||
"</Name></RespectBrowserAcceptHeaderController.Employee>";
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/RespectBrowserAcceptHeader/EmployeeInfoWithProduces");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("application/xml; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
var responseData = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedResponseData, responseData);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/xml,*/*;0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_WithContentTypeHeader_ContentTypeIsHonored(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
client.DefaultRequestHeaders.Add("Accept", acceptHeader);
|
||||
var requestData = "<RespectBrowserAcceptHeaderController.Employee xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"" +
|
||||
" xmlns=\"http://schemas.datacontract.org/2004/07/FormatterWebSite.Controllers\"><Id>35</Id><Name>Jimmy" +
|
||||
"</Name></RespectBrowserAcceptHeaderController.Employee>";
|
||||
|
||||
// Act
|
||||
var response = await client.PostAsync("http://localhost/RespectBrowserAcceptHeader/CreateEmployee",
|
||||
new StringContent(requestData, Encoding.UTF8, "application/xml"));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
Assert.Equal("application/xml; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
var responseData = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(requestData, responseData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
|
|
@ -14,4 +14,9 @@
|
|||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties project_1json__JSONSchema="http://www.asp.net/media/4878834/project.json" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
|
|
@ -83,11 +83,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
setup.Configure(mvcOptions);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(4, mvcOptions.OutputFormatters.Count);
|
||||
Assert.Equal(3, mvcOptions.OutputFormatters.Count);
|
||||
Assert.IsType<HttpNoContentOutputFormatter>(mvcOptions.OutputFormatters[0].Instance);
|
||||
Assert.IsType<TextPlainFormatter>(mvcOptions.OutputFormatters[1].Instance);
|
||||
Assert.IsType<JsonOutputFormatter>(mvcOptions.OutputFormatters[2].Instance);
|
||||
Assert.IsType<XmlDataContractSerializerOutputFormatter>(mvcOptions.OutputFormatters[3].Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -101,9 +100,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
setup.Configure(mvcOptions);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, mvcOptions.InputFormatters.Count);
|
||||
Assert.Equal(1, mvcOptions.InputFormatters.Count);
|
||||
Assert.IsType<JsonInputFormatter>(mvcOptions.InputFormatters[0].Instance);
|
||||
Assert.IsType<XmlDataContractSerializerInputFormatter>(mvcOptions.InputFormatters[1].Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -122,6 +120,20 @@ namespace Microsoft.AspNet.Mvc
|
|||
Assert.IsType<DataMemberModelValidatorProvider>(mvcOptions.ModelValidatorProviders[1].Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Setup_IgnoresAcceptHeaderHavingWildCardMediaAndSubMediaTypes()
|
||||
{
|
||||
// Arrange
|
||||
var mvcOptions = new MvcOptions();
|
||||
var setup = new MvcOptionsSetup();
|
||||
|
||||
// Act
|
||||
setup.Configure(mvcOptions);
|
||||
|
||||
// Assert
|
||||
Assert.False(mvcOptions.RespectBrowserAcceptHeader);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Setup_SetsUpExcludeFromValidationDelegates()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -73,6 +74,13 @@ namespace System.Web.Http
|
|||
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(formatters.Object);
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
return services.Object;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -73,6 +74,13 @@ namespace System.Web.Http
|
|||
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(formatters.Object);
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
return services.Object;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Microsoft.AspNet.Http.Core;
|
|||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -86,6 +87,13 @@ namespace System.Web.Http
|
|||
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(formatters.Object);
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
return services.Object;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -75,6 +76,13 @@ namespace System.Web.Http
|
|||
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(formatters.Object);
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
return services.Object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -48,6 +49,13 @@ namespace System.Web.Http
|
|||
.Setup(s => s.GetService(typeof(IOutputFormattersProvider)))
|
||||
.Returns(formatters.Object);
|
||||
|
||||
var options = new Mock<IOptions<MvcOptions>>();
|
||||
options.SetupGet(o => o.Options)
|
||||
.Returns(new MvcOptions());
|
||||
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(options.Object);
|
||||
|
||||
return services.Object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
|
|
@ -16,6 +17,11 @@ namespace ActionResultsWebSite
|
|||
app.UseServices(services =>
|
||||
{
|
||||
services.AddMvc(configuration);
|
||||
|
||||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
options.AddXmlDataContractSerializerFormatter();
|
||||
});
|
||||
});
|
||||
|
||||
app.UseMvc(routes =>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace FormatterWebSite.Controllers
|
||||
{
|
||||
public class RespectBrowserAcceptHeaderController : Controller
|
||||
{
|
||||
[HttpGet]
|
||||
public Employee EmployeeInfo()
|
||||
{
|
||||
return new Employee()
|
||||
{
|
||||
Id = 10,
|
||||
Name = "John"
|
||||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Produces("application/xml")]
|
||||
public Employee EmployeeInfoWithProduces()
|
||||
{
|
||||
return new Employee()
|
||||
{
|
||||
Id = 20,
|
||||
Name = "Mike"
|
||||
};
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult CreateEmployee([FromBody]Employee employee)
|
||||
{
|
||||
if(!ModelState.IsValid)
|
||||
{
|
||||
return HttpBadRequest(ModelState);
|
||||
}
|
||||
|
||||
return new ObjectResult(employee);
|
||||
}
|
||||
|
||||
public class Employee
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,4 +15,9 @@
|
|||
<DevelopmentServerPort>49634</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties project_1json__JSONSchema="http://www.asp.net/media/4878834/project.json" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
|
|
@ -24,6 +24,8 @@ namespace FormatterWebSite
|
|||
{
|
||||
options.ValidationExcludeFilters.Add(typeof(Developer));
|
||||
options.ValidationExcludeFilters.Add(typeof(Supplier));
|
||||
|
||||
options.AddXmlDataContractSerializerFormatter();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ namespace ModelBindingWebSite
|
|||
{
|
||||
m.MaxModelValidationErrors = 8;
|
||||
m.ModelBinders.Insert(0, typeof(TestMetadataAwareBinder));
|
||||
|
||||
m.AddXmlDataContractSerializerFormatter();
|
||||
});
|
||||
|
||||
services.AddSingleton<ICalculator, DefaultCalculator>();
|
||||
|
|
|
|||
Loading…
Reference in New Issue