From e2787b3b84182064d88dcc6a02760fc706d45cdc Mon Sep 17 00:00:00 2001 From: Ajay Bhargav Baaskaran Date: Wed, 24 Jun 2015 16:23:38 -0700 Subject: [PATCH] [Fixes #2715] Removed formatter dependency from JsonResult and JsonViewComponentResult --- .../JsonResult.cs | 120 ++++---------- .../ViewComponents/JsonViewComponentResult.cs | 37 ++--- .../ApiController.cs | 16 +- .../ControllerTests.cs | 6 +- .../ControllerUnitTestabilityTests.cs | 2 - .../JsonResultTest.cs | 153 ++---------------- .../JsonViewComponentResultTest.cs | 80 +-------- .../ContentNegotiationTest.cs | 74 --------- .../JsonResultTest.cs | 59 +------ .../ApiControllerTest.cs | 25 +-- .../Controllers/JsonResultController.cs | 15 +- .../Controllers/JsonResultController.cs | 21 --- 12 files changed, 75 insertions(+), 533 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Extensions/JsonResult.cs b/src/Microsoft.AspNet.Mvc.Extensions/JsonResult.cs index dc036ce5be..e4cfdfe4c1 100644 --- a/src/Microsoft.AspNet.Mvc.Extensions/JsonResult.cs +++ b/src/Microsoft.AspNet.Mvc.Extensions/JsonResult.cs @@ -1,13 +1,10 @@ // 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.Collections.Generic; -using System.Diagnostics; -using System.Linq; +using System.Text; using System.Threading.Tasks; -using Microsoft.Framework.DependencyInjection; +using Microsoft.AspNet.Mvc.Internal; using Microsoft.Framework.Internal; -using Microsoft.Framework.OptionsModel; using Microsoft.Net.Http.Headers; using Newtonsoft.Json; @@ -18,13 +15,11 @@ namespace Microsoft.AspNet.Mvc /// public class JsonResult : ActionResult { - /// - /// The list of content-types used for formatting when is null or empty. - /// - public static readonly IReadOnlyList DefaultContentTypes = new MediaTypeHeaderValue[] + private readonly JsonSerializerSettings _serializerSettings; + + private static readonly MediaTypeHeaderValue DefaultContentType = new MediaTypeHeaderValue("application/json") { - MediaTypeHeaderValue.Parse("application/json"), - MediaTypeHeaderValue.Parse("text/json"), + Encoding = Encoding.UTF8 }; /// @@ -32,7 +27,7 @@ namespace Microsoft.AspNet.Mvc /// /// The value to format as JSON. public JsonResult(object value) - : this(value, formatter: null) + : this(value, serializerSettings: SerializerSettingsProvider.CreateSerializerSettings()) { } @@ -43,32 +38,15 @@ namespace Microsoft.AspNet.Mvc /// The to be used by /// the formatter. public JsonResult(object value, [NotNull] JsonSerializerSettings serializerSettings) - : this(value, formatter: new JsonOutputFormatter(serializerSettings)) - { - } - - /// - /// Creates a new with the given . - /// - /// The value to format as JSON. - /// The formatter to use, or null to choose a formatter dynamically. - public JsonResult(object value, IOutputFormatter formatter) { Value = value; - Formatter = formatter; - - ContentTypes = new List(); + _serializerSettings = serializerSettings; } /// - /// Gets or sets the list of supported Content-Types. + /// Gets or sets the representing the Content-Type header of the response. /// - public IList ContentTypes { get; set; } - - /// - /// Gets or sets the formatter. - /// - public IOutputFormatter Formatter { get; set; } + public MediaTypeHeaderValue ContentType { get; set; } /// /// Gets or sets the HTTP status code. @@ -81,80 +59,44 @@ namespace Microsoft.AspNet.Mvc public object Value { get; set; } /// - public override async Task ExecuteResultAsync([NotNull] ActionContext context) + public override Task ExecuteResultAsync([NotNull] ActionContext context) { - var objectResult = new ObjectResult(Value); + var response = context.HttpContext.Response; - // Set the content type explicitly to application/json and text/json. - // if the user has not already set it. - if (ContentTypes == null || ContentTypes.Count == 0) + var contentTypeHeader = ContentType; + if (contentTypeHeader == null) { - foreach (var contentType in DefaultContentTypes) - { - objectResult.ContentTypes.Add(contentType); - } + contentTypeHeader = DefaultContentType; } else { - objectResult.ContentTypes = ContentTypes; + if (contentTypeHeader.Encoding == null) + { + // 1. Do not modify the user supplied content type + // 2. Parse here to handle parameters apart from charset + contentTypeHeader = MediaTypeHeaderValue.Parse(contentTypeHeader.ToString()); + contentTypeHeader.Encoding = Encoding.UTF8; + } } - var formatterContext = new OutputFormatterContext() - { - HttpContext = context.HttpContext, - DeclaredType = objectResult.DeclaredType, - Object = Value, - }; - - // JsonResult expects to always find a formatter, in contrast with ObjectResult, which might return - // a 406. - var formatter = SelectFormatter(objectResult, formatterContext); - Debug.Assert(formatter != null); + response.ContentType = contentTypeHeader.ToString(); if (StatusCode != null) { - context.HttpContext.Response.StatusCode = StatusCode.Value; + response.StatusCode = StatusCode.Value; } - await formatter.WriteAsync(formatterContext); - } - - private IOutputFormatter SelectFormatter(ObjectResult objectResult, OutputFormatterContext formatterContext) - { - if (Formatter == null) + using (var writer = new HttpResponseStreamWriter(response.Body, contentTypeHeader.Encoding)) { - // If no formatter was provided, then run Conneg with the formatters configured in options. - var formatters = formatterContext - .HttpContext - .RequestServices - .GetRequiredService>() - .Options - .OutputFormatters - .OfType() - .ToArray(); - - var formatter = objectResult.SelectFormatter(formatterContext, formatters); - if (formatter == null) + using (var jsonWriter = new JsonTextWriter(writer)) { - // If the available user-configured formatters can't write this type, then fall back to the - // 'global' one. - formatter = formatterContext - .HttpContext - .RequestServices - .GetRequiredService(); - - // Run SelectFormatter again to try to choose a content type that this formatter can do. - objectResult.SelectFormatter(formatterContext, new[] { formatter }); + jsonWriter.CloseOutput = false; + var jsonSerializer = JsonSerializer.Create(_serializerSettings); + jsonSerializer.Serialize(jsonWriter, Value); } + } - return formatter; - } - else - { - // Run SelectFormatter to try to choose a content type that this formatter can do. - objectResult.SelectFormatter(formatterContext, new[] { Formatter }); - return Formatter; - } + return Task.FromResult(true); } } } diff --git a/src/Microsoft.AspNet.Mvc.Extensions/ViewComponents/JsonViewComponentResult.cs b/src/Microsoft.AspNet.Mvc.Extensions/ViewComponents/JsonViewComponentResult.cs index 688a36b917..3a18f9dd27 100644 --- a/src/Microsoft.AspNet.Mvc.Extensions/ViewComponents/JsonViewComponentResult.cs +++ b/src/Microsoft.AspNet.Mvc.Extensions/ViewComponents/JsonViewComponentResult.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Threading.Tasks; -using Microsoft.Framework.DependencyInjection; +using Microsoft.AspNet.Mvc.Internal; using Microsoft.Framework.Internal; using Newtonsoft.Json; @@ -13,12 +13,14 @@ namespace Microsoft.AspNet.Mvc /// public class JsonViewComponentResult : IViewComponentResult { + private readonly JsonSerializerSettings _serializerSettings; + /// /// Initializes a new . /// /// The value to format as JSON text. public JsonViewComponentResult(object value) - : this(value, formatter: null) + : this(value, serializerSettings: SerializerSettingsProvider.CreateSerializerSettings()) { } @@ -29,19 +31,9 @@ namespace Microsoft.AspNet.Mvc /// The to be used by /// the formatter. public JsonViewComponentResult(object value, [NotNull] JsonSerializerSettings serializerSettings) - : this(value, new JsonOutputFormatter(serializerSettings)) - { - } - - /// - /// Initializes a new . - /// - /// The value to format as JSON text. - /// The to use. - public JsonViewComponentResult(object value, JsonOutputFormatter formatter) { Value = value; - Formatter = formatter; + _serializerSettings = serializerSettings; } /// @@ -49,19 +41,18 @@ namespace Microsoft.AspNet.Mvc /// public object Value { get; } - /// - /// Gets the formatter. - /// - public JsonOutputFormatter Formatter { get; } - /// /// Renders JSON text to the output. /// /// The . public void Execute([NotNull] ViewComponentContext context) { - var formatter = Formatter ?? ResolveFormatter(context); - formatter.WriteObject(context.Writer, Value); + using (var jsonWriter = new JsonTextWriter(context.Writer)) + { + jsonWriter.CloseOutput = false; + var jsonSerializer = JsonSerializer.Create(_serializerSettings); + jsonSerializer.Serialize(jsonWriter, Value); + } } /// @@ -74,11 +65,5 @@ namespace Microsoft.AspNet.Mvc Execute(context); return Task.FromResult(true); } - - private static JsonOutputFormatter ResolveFormatter(ViewComponentContext context) - { - var services = context.ViewContext.HttpContext.RequestServices; - return services.GetRequiredService(); - } } } diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs index 29ca1ae261..51ee047790 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs @@ -11,6 +11,7 @@ using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.WebApiCompatShim; using Microsoft.Framework.Internal; +using Microsoft.Net.Http.Headers; using Newtonsoft.Json; namespace System.Web.Http @@ -257,9 +258,7 @@ namespace System.Web.Http [NonAction] public virtual JsonResult Json([NotNull] T content, [NotNull] JsonSerializerSettings serializerSettings) { - var formatter = new JsonOutputFormatter(serializerSettings); - - return new JsonResult(content, formatter); + return new JsonResult(content, serializerSettings); } /// @@ -276,12 +275,13 @@ namespace System.Web.Http [NotNull] JsonSerializerSettings serializerSettings, [NotNull] Encoding encoding) { - var formatter = new JsonOutputFormatter(serializerSettings); + var result = new JsonResult(content, serializerSettings); + result.ContentType = new MediaTypeHeaderValue("application/json") + { + Encoding = encoding + }; - formatter.SupportedEncodings.Clear(); - formatter.SupportedEncodings.Add(encoding); - - return new JsonResult(content, formatter); + return result; } /// diff --git a/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerTests.cs b/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerTests.cs index 813647ac56..187f745daf 100644 --- a/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerTests.cs +++ b/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerTests.cs @@ -1033,7 +1033,7 @@ namespace Microsoft.AspNet.Mvc.Test } [Fact] - public void Controller_Json_WithParameterValueAndSerializerSettings_SetsRespectiveValues() + public void Controller_Json_WithParameterValue_SetsRespectiveProperty() { // Arrange var controller = new TestableController(); @@ -1046,8 +1046,6 @@ namespace Microsoft.AspNet.Mvc.Test // Assert Assert.IsType(actualJsonResult); Assert.Same(data, actualJsonResult.Value); - var jsonFormatter = actualJsonResult.Formatter as JsonOutputFormatter; - Assert.Same(serializerSettings, jsonFormatter.SerializerSettings); } [Fact] @@ -1094,8 +1092,6 @@ namespace Microsoft.AspNet.Mvc.Test // Assert Assert.IsType(result); Assert.Same(input, result.Value); - var jsonFormatter = result.Formatter as JsonOutputFormatter; - Assert.Same(serializerSettings, jsonFormatter.SerializerSettings); mockHttpContext.Verify( x => x.Response.OnResponseCompleted(It.IsAny>(), It.IsAny()), Times.Once()); diff --git a/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerUnitTestabilityTests.cs b/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerUnitTestabilityTests.cs index 6307b5061b..94d30b4a05 100644 --- a/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerUnitTestabilityTests.cs +++ b/test/Microsoft.AspNet.Mvc.Extensions.Test/ControllerUnitTestabilityTests.cs @@ -228,8 +228,6 @@ namespace Microsoft.AspNet.Mvc Assert.NotNull(jsonResult.Value); Assert.Same(model, jsonResult.Value); Assert.IsType(jsonResult.Value); - var jsonFormatter = jsonResult.Formatter as JsonOutputFormatter; - Assert.Same(serializerSettings, jsonFormatter.SerializerSettings); } [Fact] diff --git a/test/Microsoft.AspNet.Mvc.Extensions.Test/JsonResultTest.cs b/test/Microsoft.AspNet.Mvc.Extensions.Test/JsonResultTest.cs index a71dc5b18e..bd59594666 100644 --- a/test/Microsoft.AspNet.Mvc.Extensions.Test/JsonResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Extensions.Test/JsonResultTest.cs @@ -1,19 +1,13 @@ // 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; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Routing; -using Microsoft.Framework.Logging; -using Microsoft.Framework.OptionsModel; using Microsoft.Net.Http.Headers; -using Moq; using Newtonsoft.Json; using Xunit; @@ -28,18 +22,12 @@ namespace Microsoft.AspNet.Mvc = new byte[] { 123, 13, 10, 32, 32, 34, 102, 111, 111, 34, 58, 32, 34, 97, 98, 99, 100, 34, 13, 10, 125 }; [Fact] - public async Task ExecuteResultAsync_OptionsFormatter_WithoutBOM() + public async Task ExecuteResultAsync_UsesDefaultContentType_IfNoContentTypeSpecified() { // Arrange var expected = _abcdUTF8Bytes; - var optionsFormatters = new List() - { - Mock.Of(), // This won't be used - new JsonOutputFormatter(), - }; - - var context = GetHttpContext(optionsFormatters); + var context = GetHttpContext(); var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor()); var result = new JsonResult(new { foo = "abcd" }); @@ -54,49 +42,16 @@ namespace Microsoft.AspNet.Mvc } [Fact] - public async Task ExecuteResultAsync_Null() + public async Task ExecuteResultAsync_NullEncoding_SetsContentTypeAndDefaultEncoding() { // Arrange var expected = _abcdUTF8Bytes; - var optionsFormatters = new List() - { - Mock.Of(), // This won't be used - new JsonOutputFormatter(), - }; - - var context = GetHttpContext(optionsFormatters); - var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor()); - - var result = new JsonResult(new { foo = "abcd" }); - - // Act - await result.ExecuteResultAsync(actionContext); - var written = GetWrittenBytes(context); - - // Assert - Assert.Equal(expected, written); - Assert.Equal("application/json; charset=utf-8", context.Response.ContentType); - } - - [Fact] - public async Task ExecuteResultAsync_OptionsFormatter_Conneg() - { - // Arrange - var expected = _abcdUTF8Bytes; - - var optionsFormatters = new List() - { - Mock.Of(), // This won't be used - new JsonOutputFormatter(), - }; - - var context = GetHttpContext(optionsFormatters); - context.Request.Headers["Accept"] = "text/json"; - + var context = GetHttpContext(); var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor()); var result = new JsonResult(new { foo = "abcd" }); + result.ContentType = new MediaTypeHeaderValue("text/json"); // Act await result.ExecuteResultAsync(actionContext); @@ -108,7 +63,7 @@ namespace Microsoft.AspNet.Mvc } [Fact] - public async Task ExecuteResultAsync_UsesPassedInFormatter() + public async Task ExecuteResultAsync_SetsContentTypeAndEncoding() { // Arrange var expected = _abcdUTF8Bytes; @@ -116,13 +71,11 @@ namespace Microsoft.AspNet.Mvc var context = GetHttpContext(); var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor()); - var formatter = new JsonOutputFormatter(); - formatter.SupportedEncodings.Clear(); - - // This is UTF-8 WITH BOM - formatter.SupportedEncodings.Add(Encoding.UTF8); - - var result = new JsonResult(new { foo = "abcd" }, formatter); + var result = new JsonResult(new { foo = "abcd" }); + result.ContentType = new MediaTypeHeaderValue("text/json") + { + Encoding = Encoding.ASCII + }; // Act await result.ExecuteResultAsync(actionContext); @@ -130,31 +83,7 @@ namespace Microsoft.AspNet.Mvc // Assert Assert.Equal(expected, written); - Assert.Equal("application/json; charset=utf-8", context.Response.ContentType); - } - - [Fact] - public async Task ExecuteResultAsync_UsesPassedInFormatter_ContentTypeSpecified() - { - // Arrange - var expected = _abcdUTF8Bytes; - - var context = GetHttpContext(); - var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor()); - - var formatter = new JsonOutputFormatter(); - formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/hal+json")); - - var result = new JsonResult(new { foo = "abcd" }, formatter); - result.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/hal+json")); - - // Act - await result.ExecuteResultAsync(actionContext); - var written = GetWrittenBytes(context); - - // Assert - Assert.Equal(expected, written); - Assert.Equal("application/hal+json; charset=utf-8", context.Response.ContentType); + Assert.Equal("text/json; charset=us-ascii", context.Response.ContentType); } [Fact] @@ -180,67 +109,11 @@ namespace Microsoft.AspNet.Mvc Assert.Equal("application/json; charset=utf-8", context.Response.ContentType); } - // If no formatter in options can match the given content-types, then use the one registered - // in services - [Fact] - public async Task ExecuteResultAsync_UsesGlobalFormatter_IfNoFormatterIsConfigured() - { - // Arrange - var expected = _abcdUTF8Bytes; - - var context = GetHttpContext(enableFallback: true); - var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor()); - - var result = new JsonResult(new { foo = "abcd" }); - - // Act - await result.ExecuteResultAsync(actionContext); - var written = GetWrittenBytes(context); - - // Assert - Assert.Equal(expected, written); - Assert.Equal("application/json; charset=utf-8", context.Response.ContentType); - } - - private HttpContext GetHttpContext( - IReadOnlyList outputFormatters = null, - bool enableFallback = false) + private HttpContext GetHttpContext() { var httpContext = new DefaultHttpContext(); httpContext.Response.Body = new MemoryStream(); - var services = new Mock(MockBehavior.Strict); - httpContext.RequestServices = services.Object; - - var options = new MvcOptions(); - if (outputFormatters != null) - { - foreach (var formatter in outputFormatters) - { - options.OutputFormatters.Add(formatter); - } - } - - var optionsAccessor = new Mock>(); - optionsAccessor.SetupGet(o => o.Options) - .Returns(options); - - services.Setup(s => s.GetService(typeof(IOptions))) - .Returns(optionsAccessor.Object); - services.Setup(s => s.GetService(typeof(IOptions))) - .Returns(optionsAccessor.Object); - services.Setup(s => s.GetService(typeof(ILogger))) - .Returns(new Mock>().Object); - - // This is the ultimate fallback, it will be used if none of the formatters from options - // work. - if (enableFallback) - { - services - .Setup(s => s.GetService(typeof(JsonOutputFormatter))) - .Returns(new JsonOutputFormatter()); - } - return httpContext; } diff --git a/test/Microsoft.AspNet.Mvc.Extensions.Test/ViewComponents/JsonViewComponentResultTest.cs b/test/Microsoft.AspNet.Mvc.Extensions.Test/ViewComponents/JsonViewComponentResultTest.cs index 0fb37c79d4..7bad79686b 100644 --- a/test/Microsoft.AspNet.Mvc.Extensions.Test/ViewComponents/JsonViewComponentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Extensions.Test/ViewComponents/JsonViewComponentResultTest.cs @@ -1,14 +1,13 @@ // 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; using System.IO; +using System.Text; using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.ViewComponents; using Microsoft.AspNet.Routing; -using Microsoft.Framework.DependencyInjection; using Moq; using Newtonsoft.Json; using Xunit; @@ -17,26 +16,6 @@ namespace Microsoft.AspNet.Mvc { public class JsonViewComponentResultTest { - [Fact] - public void Execute_SerializesData_UsingSpecifiedFormatter() - { - // Arrange - var view = Mock.Of(); - var buffer = new MemoryStream(); - var viewComponentContext = GetViewComponentContext(view, buffer); - - var expectedFormatter = new JsonOutputFormatter(); - var result = new JsonViewComponentResult(1, expectedFormatter); - - // Act - result.Execute(viewComponentContext); - buffer.Position = 0; - - // Assert - Assert.Equal(expectedFormatter, result.Formatter); - Assert.Equal("1", new StreamReader(buffer).ReadToEnd()); - } - [Fact] public void Execute_UsesFormatter_WithSpecifiedSerializerSettings() { @@ -48,65 +27,14 @@ namespace Microsoft.AspNet.Mvc var serializerSettings = new JsonSerializerSettings(); serializerSettings.Formatting = Formatting.Indented; - var result = new JsonViewComponentResult("abc", serializerSettings); + var result = new JsonViewComponentResult(new { foo = "abcd" }, serializerSettings); + viewComponentContext.ViewContext.HttpContext.Response.Body = buffer; // Act result.Execute(viewComponentContext); // Assert - Assert.Same(serializerSettings, result.Formatter.SerializerSettings); - } - - [Fact] - public void Execute_FallsbackToServices_WhenNoJsonFormatterIsProvided() - { - // Arrange - var view = Mock.Of(); - - var serviceProvider = new Mock(); - - serviceProvider - .Setup(p => p.GetService(typeof(JsonOutputFormatter))) - .Returns(new JsonOutputFormatter()) - .Verifiable(); - - var buffer = new MemoryStream(); - - var result = new JsonViewComponentResult(1); - var viewComponentContext = GetViewComponentContext(view, buffer); - viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider.Object; - - // Act - result.Execute(viewComponentContext); - buffer.Position = 0; - - // Assert - Assert.Equal("1", new StreamReader(buffer).ReadToEnd()); - serviceProvider.Verify(); - } - - [Fact] - public void Execute_Throws_IfNoFormatterCanBeResolved() - { - // Arrange - var expected = "No service for type 'Microsoft.AspNet.Mvc.JsonOutputFormatter'" + - " has been registered."; - - var view = Mock.Of(); - - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - - var buffer = new MemoryStream(); - - var result = new JsonViewComponentResult(1); - var viewComponentContext = GetViewComponentContext(view, buffer); - viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider; - - // Act - var ex = Assert.Throws(() => result.Execute(viewComponentContext)); - - // Assert - Assert.Equal(expected, ex.Message); + Assert.Equal("{\r\n \"foo\": \"abcd\"\r\n}", Encoding.UTF8.GetString(buffer.ToArray())); } private static ViewComponentContext GetViewComponentContext(IView view, Stream stream) diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ContentNegotiationTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ContentNegotiationTest.cs index b8f920101f..13d52edd07 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ContentNegotiationTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ContentNegotiationTest.cs @@ -319,80 +319,6 @@ END:VCARD Assert.Equal(expectedBody, body); } - [Fact] - public async Task JsonResult_UsesDefaultContentTypes_IfNoneAreAddedExplicitly() - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8"); - var expectedBody = "{\"MethodName\":\"ReturnJsonResult\"}"; - - // Act - var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult"); - - // Assert - Assert.Equal(expectedContentType, response.Content.Headers.ContentType); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal(expectedBody, body); - } - - [Fact] - public async Task JsonResult_UsesExplicitContentTypeAndFormatter_IfAdded() - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - var expectedContentType = MediaTypeHeaderValue.Parse("application/custom-json;charset=utf-8"); - var expectedBody = "{ MethodName = ReturnJsonResult_WithCustomMediaType }"; - - // Act - var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult_WithCustomMediaType"); - - // Assert - Assert.Equal(expectedContentType, response.Content.Headers.ContentType); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal(expectedBody, body); - } - - [Fact] - public async Task JsonResult_UsesDefaultJsonFormatter_IfNoMatchingFormatterIsFound() - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8"); - var expectedBody = "{\"MethodName\":\"ReturnJsonResult_WithCustomMediaType_NoFormatter\"}"; - - // Act - var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult_WithCustomMediaType_NoFormatter"); - - // Assert - Assert.Equal(expectedContentType, response.Content.Headers.ContentType); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal(expectedBody, body); - } - - [Fact] - public async Task JsonFormatter_SupportedMediaType_DoesNotChangeAcrossRequests() - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8"); - var expectedBody = "{\"MethodName\":\"ReturnJsonResult\"}"; - - for (int i = 0; i < 5; i++) - { - // Act and Assert - var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult"); - - Assert.Equal(expectedContentType, response.Content.Headers.ContentType); - var body = await response.Content.ReadAsStringAsync(); - Assert.Equal(expectedBody, body); - } - } - [Fact] public async Task XmlFormatter_SupportedMediaType_DoesNotChangeAcrossRequests() { diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonResultTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonResultTest.cs index 75526dfd40..6addb861ef 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonResultTest.cs @@ -17,10 +17,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests private readonly Action _app = new BasicWebSite.Startup().Configure; private readonly Action _configureServices = new BasicWebSite.Startup().ConfigureServices; - [Theory] - [InlineData("application/json")] - [InlineData("text/json")] - public async Task JsonResult_Conneg(string mediaType) + [Fact] + public async Task JsonResult_UsesDefaultContentType() { // Arrange var server = TestHelper.CreateServer(_app, SiteName, _configureServices); @@ -29,7 +27,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var url = "http://localhost/JsonResult/Plain"; var request = new HttpRequestMessage(HttpMethod.Get, url); - request.Headers.TryAddWithoutValidation("Accept", mediaType); // Act var response = await client.SendAsync(request); @@ -37,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(mediaType, response.Content.Headers.ContentType.MediaType); + Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType); Assert.Equal("{\"Message\":\"hello\"}", content); } @@ -111,56 +108,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests Assert.Equal("\"hello\"", content); } - [Theory] - [InlineData("application/json")] - [InlineData("text/json")] - public async Task JsonResult_CustomFormatter_Conneg(string mediaType) - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - - var url = "http://localhost/JsonResult/CustomFormatter"; - - var request = new HttpRequestMessage(HttpMethod.Get, url); - request.Headers.TryAddWithoutValidation("Accept", mediaType); - - // Act - var response = await client.SendAsync(request); - var content = await response.Content.ReadAsStringAsync(); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(mediaType, response.Content.Headers.ContentType.MediaType); - Assert.Equal("{\"message\":\"hello\"}", content); - } - - // Using an Accept header can't force Json to not be Json. If your accept header doesn't jive with the - // formatters/content-type configured on the result it will be ignored. - [Theory] - [InlineData("application/xml")] - [InlineData("text/xml")] - public async Task JsonResult_CustomFormatter_Conneg_Fails(string mediaType) - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - - var url = "http://localhost/JsonResult/CustomFormatter"; - - var request = new HttpRequestMessage(HttpMethod.Get, url); - request.Headers.TryAddWithoutValidation("Accept", mediaType); - - // Act - var response = await client.SendAsync(request); - var content = await response.Content.ReadAsStringAsync(); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType); - Assert.Equal("{\"message\":\"hello\"}", content); - } - [Fact] public async Task JsonResult_Uses_CustomSerializerSettings() { diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ApiControllerTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ApiControllerTest.cs index cb8e555a3c..5a15fcfffe 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ApiControllerTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ApiControllerTest.cs @@ -250,26 +250,7 @@ namespace System.Web.Http } [Fact] - public void ApiController_Json_Settings() - { - // Arrange - var controller = new ConcreteApiController(); - var product = new Product(); - var settings = new JsonSerializerSettings(); - - // Act - var result = controller.Json(product, settings); - - // Assert - var jsonResult = Assert.IsType(result); - Assert.Same(product, jsonResult.Value); - - var formatter = Assert.IsType(jsonResult.Formatter); - Assert.Same(settings, formatter.SerializerSettings); - } - - [Fact] - public void ApiController_Json_Settings_Encoding() + public void ApiController_Json_Encoding() { // Arrange var controller = new ConcreteApiController(); @@ -283,9 +264,7 @@ namespace System.Web.Http var jsonResult = Assert.IsType(result); Assert.Same(product, jsonResult.Value); - var formatter = Assert.IsType(jsonResult.Formatter); - Assert.Same(settings, formatter.SerializerSettings); - Assert.Same(Encoding.UTF8, Assert.Single(formatter.SupportedEncodings)); + Assert.Same(Encoding.UTF8, jsonResult.ContentType.Encoding); } [Fact] diff --git a/test/WebSites/BasicWebSite/Controllers/JsonResultController.cs b/test/WebSites/BasicWebSite/Controllers/JsonResultController.cs index 1772a24aa3..24b341b12d 100644 --- a/test/WebSites/BasicWebSite/Controllers/JsonResultController.cs +++ b/test/WebSites/BasicWebSite/Controllers/JsonResultController.cs @@ -17,21 +17,10 @@ namespace BasicWebSite.Controllers return Json(new { Message = "hello" }); } - public JsonResult CustomFormatter() - { - var formatter = new JsonOutputFormatter(); - formatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - - return new JsonResult(new { Message = "hello" }, formatter); - } - public JsonResult CustomContentType() { - var formatter = new JsonOutputFormatter(); - formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/message+json")); - - var result = new JsonResult(new { Message = "hello" }, formatter); - result.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/message+json")); + var result = new JsonResult(new { Message = "hello" }); + result.ContentType = MediaTypeHeaderValue.Parse("application/message+json"); return result; } diff --git a/test/WebSites/ContentNegotiationWebSite/Controllers/JsonResultController.cs b/test/WebSites/ContentNegotiationWebSite/Controllers/JsonResultController.cs index 75f11e2aff..b26eedfeda 100644 --- a/test/WebSites/ContentNegotiationWebSite/Controllers/JsonResultController.cs +++ b/test/WebSites/ContentNegotiationWebSite/Controllers/JsonResultController.cs @@ -2,32 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Mvc; -using Microsoft.Net.Http.Headers; namespace ContentNegotiationWebSite { public class JsonResultController : Controller { - public IActionResult ReturnJsonResult() - { - return new JsonResult(new { MethodName = "ReturnJsonResult" }); - } - - public IActionResult ReturnJsonResult_WithCustomMediaType() - { - var jsonResult = new JsonResult(new { MethodName = "ReturnJsonResult_WithCustomMediaType" }, - new CustomFormatter("application/custom-json")); - jsonResult.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/custom-json")); - return jsonResult; - } - - public IActionResult ReturnJsonResult_WithCustomMediaType_NoFormatter() - { - var jsonResult = new JsonResult(new { MethodName = "ReturnJsonResult_WithCustomMediaType_NoFormatter" }); - jsonResult.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/custom-json")); - return jsonResult; - } - [Produces("application/xml")] public IActionResult Produces_WithNonObjectResult() {