[Fixes #4945] Simple string returned by controller action is not a valid JSON!

This commit is contained in:
Kiran Challa 2017-01-05 17:03:35 -08:00
parent 8a74148fe1
commit 8ac6b6699f
10 changed files with 335 additions and 192 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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