[Fixes #4945] Simple string returned by controller action is not a valid JSON!
This commit is contained in:
parent
8a74148fe1
commit
8ac6b6699f
|
|
@ -11,7 +11,7 @@ using Microsoft.Extensions.Primitives;
|
|||
namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Always writes a string value to the response, regardless of requested content type.
|
||||
/// A <see cref="TextOutputFormatter"/> for simple text content.
|
||||
/// </summary>
|
||||
public class StringOutputFormatter : TextOutputFormatter
|
||||
{
|
||||
|
|
@ -29,18 +29,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
// Ignore the passed in content type, if the object is string
|
||||
// always return it as a text/plain format.
|
||||
if (context.ObjectType == typeof(string) || context.Object is string)
|
||||
{
|
||||
if (!context.ContentType.HasValue)
|
||||
{
|
||||
var mediaType = SupportedMediaTypes[0];
|
||||
var encoding = SupportedEncodings[0];
|
||||
context.ContentType = new StringSegment(MediaType.ReplaceEncoding(mediaType, encoding));
|
||||
}
|
||||
|
||||
return true;
|
||||
// Call into base to check if the current request's content type is a supported media type.
|
||||
return base.CanWriteResult(context);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -12,39 +12,52 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||
{
|
||||
public class TextPlainFormatterTests
|
||||
public class StringOutputFormatterTests
|
||||
{
|
||||
public static IEnumerable<object[]> OutputFormatterContextValues
|
||||
public static IEnumerable<object[]> CanWriteStringsData
|
||||
{
|
||||
get
|
||||
{
|
||||
// object value, bool useDeclaredTypeAsString, bool expectedCanWriteResult
|
||||
yield return new object[] { "valid value", true, true };
|
||||
yield return new object[] { null, true, true };
|
||||
yield return new object[] { null, false, false };
|
||||
yield return new object[] { new object(), false, false };
|
||||
// object value, bool useDeclaredTypeAsString
|
||||
yield return new object[] { "declared and runtime type are same", true };
|
||||
yield return new object[] { "declared and runtime type are different", false };
|
||||
yield return new object[] { null, true };
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanWriteResult_SetsAcceptContentType()
|
||||
public static TheoryData<object> CannotWriteNonStringsData
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TheoryData<object>()
|
||||
{
|
||||
null,
|
||||
new object()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/json")]
|
||||
[InlineData("application/xml")]
|
||||
public void CannotWriteUnsupportedMediaType(string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new StringOutputFormatter();
|
||||
var expectedContentType = new StringSegment("application/json");
|
||||
var expectedContentType = new StringSegment(contentType);
|
||||
|
||||
var context = new OutputFormatterWriteContext(
|
||||
new DefaultHttpContext(),
|
||||
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
||||
typeof(string),
|
||||
"Thisisastring");
|
||||
context.ContentType = expectedContentType;
|
||||
context.ContentType = new StringSegment(contentType);
|
||||
|
||||
// Act
|
||||
var result = formatter.CanWriteResult(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.False(result);
|
||||
Assert.Equal(expectedContentType, context.ContentType);
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +66,6 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
{
|
||||
// Arrange
|
||||
var formatter = new StringOutputFormatter();
|
||||
|
||||
var context = new OutputFormatterWriteContext(
|
||||
new DefaultHttpContext(),
|
||||
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
||||
|
|
@ -65,18 +77,17 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Equal(new StringSegment("text/plain; charset=utf-8"), context.ContentType);
|
||||
Assert.Equal(new StringSegment("text/plain"), context.ContentType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(OutputFormatterContextValues))]
|
||||
public void CanWriteResult_ReturnsTrueForStringTypes(
|
||||
[MemberData(nameof(CanWriteStringsData))]
|
||||
public void CanWriteStrings(
|
||||
object value,
|
||||
bool useDeclaredTypeAsString,
|
||||
bool expectedCanWriteResult)
|
||||
bool useDeclaredTypeAsString)
|
||||
{
|
||||
// Arrange
|
||||
var expectedContentType = new StringSegment("application/json");
|
||||
var expectedContentType = new StringSegment("text/plain");
|
||||
|
||||
var formatter = new StringOutputFormatter();
|
||||
var type = useDeclaredTypeAsString ? typeof(string) : typeof(object);
|
||||
|
|
@ -86,13 +97,35 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
||||
type,
|
||||
value);
|
||||
context.ContentType = expectedContentType;
|
||||
context.ContentType = new StringSegment("text/plain");
|
||||
|
||||
// Act
|
||||
var result = formatter.CanWriteResult(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedCanWriteResult, result);
|
||||
Assert.True(result);
|
||||
Assert.Equal(expectedContentType, context.ContentType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CannotWriteNonStringsData))]
|
||||
public void CannotWriteNonStrings(object value)
|
||||
{
|
||||
// Arrange
|
||||
var expectedContentType = new StringSegment("text/plain");
|
||||
var formatter = new StringOutputFormatter();
|
||||
var context = new OutputFormatterWriteContext(
|
||||
new DefaultHttpContext(),
|
||||
new TestHttpResponseStreamWriterFactory().CreateWriter,
|
||||
typeof(object),
|
||||
value);
|
||||
context.ContentType = new StringSegment("text/plain");
|
||||
|
||||
// Act
|
||||
var result = formatter.CanWriteResult(context);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.Equal(expectedContentType, context.ContentType);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,33 +345,31 @@ END:VCARD
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task ObjectResult_WithStringReturnType_DefaultToTextPlain(bool matchFormatterOnObjectType)
|
||||
[InlineData(null)]
|
||||
[InlineData("text/plain")]
|
||||
[InlineData("text/plain; charset=utf-8")]
|
||||
[InlineData("text/html, application/xhtml+xml, image/jxr, */*")] // typical browser accept header
|
||||
public async Task ObjectResult_WithStringReturnType_DefaultToTextPlain(string acceptMediaType)
|
||||
{
|
||||
// Arrange
|
||||
var targetUri = "http://localhost/FallbackOnTypeBasedMatch/ReturnString?matchFormatterOnObjectType=true" +
|
||||
matchFormatterOnObjectType;
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, targetUri);
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "FallbackOnTypeBasedMatch/ReturnString");
|
||||
request.Headers.Accept.ParseAdd(acceptMediaType);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("text/plain", response.Content.Headers.ContentType.MediaType);
|
||||
Assert.Equal("text/plain; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
var actualBody = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Hello World!", actualBody);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task ObjectResult_WithStringReturnType_SetsMediaTypeToAccept(bool matchFormatterOnObjectType)
|
||||
[Fact]
|
||||
public async Task ObjectResult_WithStringReturnType_AndNonTextPlainMediaType_DoesNotReturnTextPlain()
|
||||
{
|
||||
// Arrange
|
||||
var targetUri = "http://localhost/FallbackOnTypeBasedMatch/ReturnString?matchFormatterOnObjectType=" +
|
||||
matchFormatterOnObjectType;
|
||||
var targetUri = "http://localhost/FallbackOnTypeBasedMatch/ReturnString";
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, targetUri);
|
||||
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||
|
||||
|
|
@ -380,9 +378,9 @@ END:VCARD
|
|||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
var actualBody = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal("Hello World!", actualBody);
|
||||
Assert.Equal("\"Hello World!\"", actualBody);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
// 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 System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
/// <summary>
|
||||
/// These tests are for scenarios when <see cref="MvcOptions.RespectBrowserAcceptHeader"/> is <c>False</c>, which is the default.
|
||||
/// </summary>
|
||||
public class DoNotRespectBrowserAcceptHeaderTests : IClassFixture<MvcTestFixture<FormatterWebSite.Startup>>
|
||||
{
|
||||
public DoNotRespectBrowserAcceptHeaderTests(MvcTestFixture<FormatterWebSite.Startup> fixture)
|
||||
{
|
||||
Client = fixture.Client;
|
||||
}
|
||||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/xml,*/*;q=0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_FirstFormatterInListWritesResponse(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var request = RequestWithAccept("http://localhost/DoNotRespectBrowserAcceptHeader/EmployeeInfo", acceptHeader);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
// Mono issue - https://github.com/aspnet/External/issues/18
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
[InlineData("application/xml,*/*;q=0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_ProducesAttributeIsHonored(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var request = RequestWithAccept(
|
||||
"http://localhost/DoNotRespectBrowserAcceptHeader/EmployeeInfoWithProduces",
|
||||
acceptHeader);
|
||||
var expectedResponseData =
|
||||
"<DoNotRespectBrowserAcceptHeaderController.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></DoNotRespectBrowserAcceptHeaderController.Employee>";
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// 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();
|
||||
XmlAssert.Equal(expectedResponseData, responseData);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
// Mono issue - https://github.com/aspnet/External/issues/18
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
[InlineData("application/xml,*/*;q=0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_WithContentTypeHeader_ContentTypeIsIgnored(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var requestData =
|
||||
"<DoNotRespectBrowserAcceptHeaderController.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></DoNotRespectBrowserAcceptHeaderController.Employee>";
|
||||
var expectedResponseData = @"{""id"":35,""name"":""Jimmy""}";
|
||||
var request = RequestWithAccept("http://localhost/DoNotRespectBrowserAcceptHeader/CreateEmployee", acceptHeader);
|
||||
request.Content = new StringContent(requestData, Encoding.UTF8, "application/xml");
|
||||
request.Method = HttpMethod.Post;
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
|
||||
// Site uses default output formatter (ignores Accept header) because that header contained a wildcard match.
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
|
||||
var responseData = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedResponseData, responseData);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
// Mono issue - https://github.com/aspnet/External/issues/18
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
[InlineData("application/xml,application/json;q=0.2")]
|
||||
[InlineData("application/xml,application/json")]
|
||||
public async Task AllMediaRangeAcceptHeader_WithExactMatch_ReturnsExpectedContent(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
var requestData =
|
||||
"<DoNotRespectBrowserAcceptHeaderController.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></DoNotRespectBrowserAcceptHeaderController.Employee>";
|
||||
var request = RequestWithAccept("http://localhost/DoNotRespectBrowserAcceptHeader/CreateEmployee", acceptHeader);
|
||||
request.Content = new StringContent(requestData, Encoding.UTF8, "application/xml");
|
||||
request.Method = HttpMethod.Post;
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
private static HttpRequestMessage RequestWithAccept(string url, string accept)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.Add("Accept", accept);
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,31 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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 System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class RespectBrowserAcceptHeaderTests : IClassFixture<MvcTestFixture<FormatterWebSite.Startup>>
|
||||
/// <summary>
|
||||
/// These tests are for scenarios when <see cref="MvcOptions.RespectBrowserAcceptHeader"/> is <c>True</c>(default is False).
|
||||
/// </summary>
|
||||
public class RespectBrowserAcceptHeaderTests : IClassFixture<MvcTestFixture<FormatterWebSite.StartupWithRespectBrowserAcceptHeader>>
|
||||
{
|
||||
public RespectBrowserAcceptHeaderTests(MvcTestFixture<FormatterWebSite.Startup> fixture)
|
||||
public RespectBrowserAcceptHeaderTests(MvcTestFixture<FormatterWebSite.StartupWithRespectBrowserAcceptHeader> fixture)
|
||||
{
|
||||
Client = fixture.Client;
|
||||
}
|
||||
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/xml,*/*;q=0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_FirstFormatterInListWritesResponse(string acceptHeader)
|
||||
[Fact]
|
||||
public async Task ReturnStringFromAction_StringOutputFormatterDoesNotWriteTheResponse()
|
||||
{
|
||||
// Arrange
|
||||
var request = RequestWithAccept("http://localhost/RespectBrowserAcceptHeader/EmployeeInfo", acceptHeader);
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "RespectBrowserAcceptHeader/ReturnString");
|
||||
request.Headers.Accept.ParseAdd("text/html, application/json, image/jpeg, */*; q=.2");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
|
@ -37,24 +36,15 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
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);
|
||||
Assert.Equal("\"Hello World!\"", responseData);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
// Mono issue - https://github.com/aspnet/External/issues/18
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
[InlineData("application/xml,*/*;q=0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_ProducesAttributeIsHonored(string acceptHeader)
|
||||
[Fact]
|
||||
public async Task ReturnStringFromAction_AcceptHeaderWithTextPlain_WritesTextPlainResponse()
|
||||
{
|
||||
// Arrange
|
||||
var request = RequestWithAccept(
|
||||
"http://localhost/RespectBrowserAcceptHeader/EmployeeInfoWithProduces",
|
||||
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>";
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "RespectBrowserAcceptHeader/ReturnString");
|
||||
request.Headers.Accept.ParseAdd("text/plain; charset=utf-8");
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
|
@ -63,77 +53,9 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
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());
|
||||
Assert.Equal("text/plain; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
var responseData = await response.Content.ReadAsStringAsync();
|
||||
XmlAssert.Equal(expectedResponseData, responseData);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
// Mono issue - https://github.com/aspnet/External/issues/18
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
[InlineData("application/xml,*/*;q=0.2")]
|
||||
[InlineData("application/xml,*/*")]
|
||||
public async Task AllMediaRangeAcceptHeader_WithContentTypeHeader_ContentTypeIsIgnored(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
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>";
|
||||
var expectedResponseData = @"{""id"":35,""name"":""Jimmy""}";
|
||||
var request = RequestWithAccept("http://localhost/RespectBrowserAcceptHeader/CreateEmployee", acceptHeader);
|
||||
request.Content = new StringContent(requestData, Encoding.UTF8, "application/xml");
|
||||
request.Method = HttpMethod.Post;
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.NotNull(response.Content);
|
||||
Assert.NotNull(response.Content.Headers.ContentType);
|
||||
|
||||
// Site uses default output formatter (ignores Accept header) because that header contained a wildcard match.
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
|
||||
var responseData = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedResponseData, responseData);
|
||||
}
|
||||
|
||||
[ConditionalTheory]
|
||||
// Mono issue - https://github.com/aspnet/External/issues/18
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
[InlineData("application/xml,application/json;q=0.2")]
|
||||
[InlineData("application/xml,application/json")]
|
||||
public async Task AllMediaRangeAcceptHeader_WithExactMatch_ReturnsExpectedContent(string acceptHeader)
|
||||
{
|
||||
// Arrange
|
||||
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>";
|
||||
var request = RequestWithAccept("http://localhost/RespectBrowserAcceptHeader/CreateEmployee", acceptHeader);
|
||||
request.Content = new StringContent(requestData, Encoding.UTF8, "application/xml");
|
||||
request.Method = HttpMethod.Post;
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
private static HttpRequestMessage RequestWithAccept(string url, string accept)
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.Add("Accept", accept);
|
||||
|
||||
return request;
|
||||
Assert.Equal("Hello World!", responseData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// 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.AspNetCore.Mvc;
|
||||
|
||||
namespace FormatterWebSite.Controllers
|
||||
{
|
||||
public class DoNotRespectBrowserAcceptHeaderController : 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 BadRequest(ModelState);
|
||||
}
|
||||
|
||||
return new ObjectResult(employee);
|
||||
}
|
||||
|
||||
public class Employee
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// 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.AspNetCore.Mvc;
|
||||
|
|
@ -8,42 +8,9 @@ namespace FormatterWebSite.Controllers
|
|||
public class RespectBrowserAcceptHeaderController : Controller
|
||||
{
|
||||
[HttpGet]
|
||||
public Employee EmployeeInfo()
|
||||
public string ReturnString()
|
||||
{
|
||||
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 BadRequest(ModelState);
|
||||
}
|
||||
|
||||
return new ObjectResult(employee);
|
||||
}
|
||||
|
||||
public class Employee
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
return "Hello World!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
// 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 System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
namespace FormatterWebSite
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseStartup<Startup>()
|
||||
.UseKestrel()
|
||||
.UseIISIntegration()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
// 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 System.IO;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
|
@ -34,18 +32,6 @@ namespace FormatterWebSite
|
|||
defaults: new { controller = "Home", action = "Index" });
|
||||
});
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseStartup<Startup>()
|
||||
.UseKestrel()
|
||||
.UseIISIntegration()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// 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.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FormatterWebSite
|
||||
{
|
||||
public class StartupWithRespectBrowserAcceptHeader
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc(options =>
|
||||
{
|
||||
options.RespectBrowserAcceptHeader = true;
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseCultureReplacer();
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("ActionAsMethod", "{controller}/{action}",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue