diff --git a/src/Microsoft.AspNet.Mvc.Core/ContentResult.cs b/src/Microsoft.AspNet.Mvc.Core/ContentResult.cs index 3936736187..f57d38fab1 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ContentResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ContentResult.cs @@ -34,31 +34,18 @@ namespace Microsoft.AspNet.Mvc public override async Task ExecuteResultAsync([NotNull] ActionContext context) { var response = context.HttpContext.Response; - var contentTypeHeader = ContentType; - Encoding encoding; - if (contentTypeHeader == null) - { - contentTypeHeader = DefaultContentType; - encoding = Encoding.UTF8; - } - else - { - if (contentTypeHeader.Encoding == null) - { - // Do not modify the user supplied content type, so copy it instead - contentTypeHeader = contentTypeHeader.Copy(); - contentTypeHeader.Encoding = Encoding.UTF8; - encoding = Encoding.UTF8; - } - else - { - encoding = contentTypeHeader.Encoding; - } + if (contentTypeHeader != null && contentTypeHeader.Encoding == null) + { + // Do not modify the user supplied content type, so copy it instead + contentTypeHeader = contentTypeHeader.Copy(); + contentTypeHeader.Encoding = Encoding.UTF8; } - - response.ContentType = contentTypeHeader.ToString(); + + response.ContentType = contentTypeHeader?.ToString() + ?? response.ContentType + ?? DefaultContentType.ToString(); if (StatusCode != null) { @@ -67,7 +54,7 @@ namespace Microsoft.AspNet.Mvc if (Content != null) { - await response.WriteAsync(Content, encoding); + await response.WriteAsync(Content, contentTypeHeader?.Encoding ?? DefaultContentType.Encoding); } } } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewExecutor.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewExecutor.cs index 68d05f6d8e..f9c176f574 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewExecutor.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewExecutor.cs @@ -36,17 +36,16 @@ namespace Microsoft.AspNet.Mvc { var response = actionContext.HttpContext.Response; - contentType = contentType ?? DefaultContentType; - if (contentType.Encoding == null) + if (contentType != null && contentType.Encoding == null) { // Do not modify the user supplied content type, so copy it instead contentType = contentType.Copy(); contentType.Encoding = Encoding.UTF8; } - response.ContentType = contentType.ToString(); + response.ContentType = contentType?.ToString() ?? response.ContentType ?? DefaultContentType.ToString(); - using (var writer = new HttpResponseStreamWriter(response.Body, contentType.Encoding)) + using (var writer = new HttpResponseStreamWriter(response.Body, contentType?.Encoding ?? DefaultContentType.Encoding)) { var viewContext = new ViewContext( actionContext, diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ContentResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ContentResultTest.cs index 7d40dd3fe3..5fe62ab730 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ContentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ContentResultTest.cs @@ -78,36 +78,68 @@ namespace Microsoft.AspNet.Mvc Assert.Equal("text/plain; charset=utf-7", httpContext.Response.ContentType); } - public static TheoryData ContentResultContentTypeData + public static TheoryData ContentResultContentTypeData { get { - return new TheoryData + return new TheoryData { { null, "κόσμε", + null, "text/plain; charset=utf-8", new byte[] { 206, 186, 225, 189, 185, 207, 131, 206, 188, 206, 181 } //utf-8 without BOM }, { new MediaTypeHeaderValue("text/foo"), "κόσμε", + null, "text/foo; charset=utf-8", new byte[] { 206, 186, 225, 189, 185, 207, 131, 206, 188, 206, 181 } //utf-8 without BOM }, { MediaTypeHeaderValue.Parse("text/foo;p1=p1-value"), "κόσμε", + null, "text/foo; p1=p1-value; charset=utf-8", new byte[] { 206, 186, 225, 189, 185, 207, 131, 206, 188, 206, 181 } //utf-8 without BOM }, { new MediaTypeHeaderValue("text/foo") { Encoding = Encoding.ASCII }, "abcd", + null, "text/foo; charset=us-ascii", new byte[] { 97, 98, 99, 100 } - } + }, + { + null, + "abcd", + "text/bar", + "text/bar", + new byte[] { 97, 98, 99, 100 } + }, + { + null, + "abcd", + "application/xml; charset=us-ascii", + "application/xml; charset=us-ascii", + new byte[] { 97, 98, 99, 100 } + }, + { + null, + "abcd", + "Invalid content type", + "Invalid content type", + new byte[] { 97, 98, 99, 100 } + }, + { + new MediaTypeHeaderValue("text/foo") { Charset = "us-ascii" }, + "abcd", + "text/bar", + "text/foo; charset=us-ascii", + new byte[] { 97, 98, 99, 100 } + }, }; } } @@ -117,6 +149,7 @@ namespace Microsoft.AspNet.Mvc public async Task ContentResult_ExecuteResultAsync_SetContentTypeAndEncoding_OnResponse( MediaTypeHeaderValue contentType, string content, + string responseContentType, string expectedContentType, byte[] expectedContentData) { @@ -129,6 +162,7 @@ namespace Microsoft.AspNet.Mvc var httpContext = GetHttpContext(); var memoryStream = new MemoryStream(); httpContext.Response.Body = memoryStream; + httpContext.Response.ContentType = responseContentType; var actionContext = GetActionContext(httpContext); // Act diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewExecutorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewExecutorTest.cs index 08957529c5..cf5e733cef 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewExecutorTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewExecutorTest.cs @@ -2,14 +2,12 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Routing; -using Microsoft.AspNet.Testing; using Microsoft.Net.Http.Headers; using Moq; using Xunit; @@ -18,32 +16,60 @@ namespace Microsoft.AspNet.Mvc { public class ViewExecutorTest { - public static TheoryData ViewExecutorSetsContentTypeAndEncodingData + public static TheoryData ViewExecutorSetsContentTypeAndEncodingData { get { - return new TheoryData + return new TheoryData { { + null, null, "text/html; charset=utf-8", new byte[] { 97, 98, 99, 100 } }, { new MediaTypeHeaderValue("text/foo"), + null, "text/foo; charset=utf-8", new byte[] { 97, 98, 99, 100 } }, { MediaTypeHeaderValue.Parse("text/foo; p1=p1-value"), + null, "text/foo; p1=p1-value; charset=utf-8", new byte[] { 97, 98, 99, 100 } }, { new MediaTypeHeaderValue("text/foo") { Charset = "us-ascii" }, + null, "text/foo; charset=us-ascii", new byte[] { 97, 98, 99, 100 } - } + }, + { + null, + "text/bar", + "text/bar", + new byte[] { 97, 98, 99, 100 } + }, + { + null, + "application/xml; charset=us-ascii", + "application/xml; charset=us-ascii", + new byte[] { 97, 98, 99, 100 } + }, + { + null, + "Invalid content type", + "Invalid content type", + new byte[] { 97, 98, 99, 100 } + }, + { + new MediaTypeHeaderValue("text/foo") { Charset = "us-ascii" }, + "text/bar", + "text/foo; charset=us-ascii", + new byte[] { 97, 98, 99, 100 } + }, }; } } @@ -52,6 +78,7 @@ namespace Microsoft.AspNet.Mvc [MemberData(nameof(ViewExecutorSetsContentTypeAndEncodingData))] public async Task ExecuteAsync_SetsContentTypeAndEncoding( MediaTypeHeaderValue contentType, + string responseContentType, string expectedContentType, byte[] expectedContentData) { @@ -68,6 +95,7 @@ namespace Microsoft.AspNet.Mvc var context = new DefaultHttpContext(); var memoryStream = new MemoryStream(); context.Response.Body = memoryStream; + context.Response.ContentType = responseContentType; var actionContext = new ActionContext(context, new RouteData(),