[Fixes #1791]Remove XML formatter from defaults

This commit is contained in:
Kiran Challa 2015-01-12 13:25:59 -08:00
parent 9aff289dfe
commit 02f4ca9f05
27 changed files with 508 additions and 50 deletions

View File

@ -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();
});
});
}

View File

@ -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();
}

View File

@ -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>

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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());

View File

@ -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;
}

View File

@ -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)))

View File

@ -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;
}

View File

@ -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; }
}
}
}

View File

@ -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(),

View File

@ -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)

View File

@ -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>();

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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()
{

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 =>

View File

@ -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; }
}
}
}

View File

@ -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>

View File

@ -24,6 +24,8 @@ namespace FormatterWebSite
{
options.ValidationExcludeFilters.Add(typeof(Developer));
options.ValidationExcludeFilters.Add(typeof(Supplier));
options.AddXmlDataContractSerializerFormatter();
});
});

View File

@ -23,6 +23,8 @@ namespace ModelBindingWebSite
{
m.MaxModelValidationErrors = 8;
m.ModelBinders.Insert(0, typeof(TestMetadataAwareBinder));
m.AddXmlDataContractSerializerFormatter();
});
services.AddSingleton<ICalculator, DefaultCalculator>();