[Fixes #1216] Provide a property on JsonOutputFormatter to set serializer settings
[Fixes #1221] Rename OutputFormatter's WriteResponseContentHeaders to WriteResponseHeaders [Fixes #932] Setting Json Serializer Settings
This commit is contained in:
parent
ebf64ce4e3
commit
e985c22528
|
|
@ -58,7 +58,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("value");
|
throw new ArgumentNullException(nameof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
_jsonSerializerSettings = value;
|
_jsonSerializerSettings = value;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// 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.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
|
|
@ -10,29 +11,33 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class JsonOutputFormatter : OutputFormatter
|
public class JsonOutputFormatter : OutputFormatter
|
||||||
{
|
{
|
||||||
private readonly JsonSerializerSettings _settings;
|
private JsonSerializerSettings _serializerSettings;
|
||||||
private readonly bool _indent;
|
|
||||||
|
public JsonOutputFormatter()
|
||||||
public JsonOutputFormatter([NotNull] JsonSerializerSettings settings, bool indent)
|
|
||||||
{
|
{
|
||||||
_settings = settings;
|
|
||||||
_indent = indent;
|
|
||||||
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
||||||
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/json"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/json"));
|
||||||
|
|
||||||
|
_serializerSettings = new JsonSerializerSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JsonSerializerSettings CreateDefaultSettings()
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>.
|
||||||
|
/// </summary>
|
||||||
|
public JsonSerializerSettings SerializerSettings
|
||||||
{
|
{
|
||||||
return new JsonSerializerSettings()
|
get { return _serializerSettings; }
|
||||||
|
set
|
||||||
{
|
{
|
||||||
MissingMemberHandling = MissingMemberHandling.Ignore,
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
// Do not change this setting
|
_serializerSettings = value;
|
||||||
// Setting this to None prevents Json.NET from loading malicious, unsafe, or security-sensitive types.
|
}
|
||||||
TypeNameHandling = TypeNameHandling.None
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteObject([NotNull] TextWriter writer, object value)
|
public void WriteObject([NotNull] TextWriter writer, object value)
|
||||||
|
|
@ -47,11 +52,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private JsonWriter CreateJsonWriter(TextWriter writer)
|
private JsonWriter CreateJsonWriter(TextWriter writer)
|
||||||
{
|
{
|
||||||
var jsonWriter = new JsonTextWriter(writer);
|
var jsonWriter = new JsonTextWriter(writer);
|
||||||
if (_indent)
|
|
||||||
{
|
|
||||||
jsonWriter.Formatting = Formatting.Indented;
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonWriter.CloseOutput = false;
|
jsonWriter.CloseOutput = false;
|
||||||
|
|
||||||
return jsonWriter;
|
return jsonWriter;
|
||||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
private JsonSerializer CreateJsonSerializer()
|
private JsonSerializer CreateJsonSerializer()
|
||||||
{
|
{
|
||||||
var jsonSerializer = JsonSerializer.Create(_settings);
|
var jsonSerializer = JsonSerializer.Create(_serializerSettings);
|
||||||
return jsonSerializer;
|
return jsonSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,15 +157,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task WriteAsync([NotNull] OutputFormatterContext context)
|
public async Task WriteAsync([NotNull] OutputFormatterContext context)
|
||||||
{
|
{
|
||||||
WriteResponseContentHeaders(context);
|
WriteResponseHeaders(context);
|
||||||
await WriteResponseBodyAsync(context);
|
await WriteResponseBodyAsync(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the content-type headers with charset value to the HttpResponse.
|
/// Sets the headers on <see cref="Microsoft.AspNet.Http.HttpResponse"/> object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The formatter context associated with the call.</param>
|
/// <param name="context">The formatter context associated with the call.</param>
|
||||||
public virtual void WriteResponseContentHeaders([NotNull] OutputFormatterContext context)
|
public virtual void WriteResponseHeaders([NotNull] OutputFormatterContext context)
|
||||||
{
|
{
|
||||||
var selectedMediaType = context.SelectedContentType;
|
var selectedMediaType = context.SelectedContentType;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,39 +9,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class JsonViewComponentResult : IViewComponentResult
|
public class JsonViewComponentResult : IViewComponentResult
|
||||||
{
|
{
|
||||||
private JsonSerializerSettings _jsonSerializerSettings;
|
|
||||||
|
|
||||||
public JsonViewComponentResult([NotNull] object data)
|
public JsonViewComponentResult([NotNull] object data)
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
_jsonSerializerSettings = JsonOutputFormatter.CreateDefaultSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Data { get; private set; }
|
public object Data { get; private set; }
|
||||||
|
|
||||||
public JsonSerializerSettings SerializerSettings
|
|
||||||
{
|
|
||||||
get { return _jsonSerializerSettings; }
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("value");
|
|
||||||
}
|
|
||||||
|
|
||||||
_jsonSerializerSettings = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether to indent elements when writing data.
|
|
||||||
/// </summary>
|
|
||||||
public bool Indent { get; set; }
|
|
||||||
|
|
||||||
public void Execute([NotNull] ViewComponentContext context)
|
public void Execute([NotNull] ViewComponentContext context)
|
||||||
{
|
{
|
||||||
var formatter = new JsonOutputFormatter(SerializerSettings, Indent);
|
var formatter = new JsonOutputFormatter();
|
||||||
formatter.WriteObject(context.Writer, Data);
|
formatter.WriteObject(context.Writer, Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Set up default output formatters.
|
// Set up default output formatters.
|
||||||
options.OutputFormatters.Add(new HttpNoContentOutputFormatter());
|
options.OutputFormatters.Add(new HttpNoContentOutputFormatter());
|
||||||
options.OutputFormatters.Add(new TextPlainFormatter());
|
options.OutputFormatters.Add(new TextPlainFormatter());
|
||||||
options.OutputFormatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(),
|
options.OutputFormatters.Add(new JsonOutputFormatter());
|
||||||
indent: false));
|
|
||||||
options.OutputFormatters.Add(
|
options.OutputFormatters.Add(
|
||||||
new XmlDataContractSerializerOutputFormatter(XmlOutputFormatter.GetDefaultXmlWriterSettings()));
|
new XmlDataContractSerializerOutputFormatter(XmlOutputFormatter.GetDefaultXmlWriterSettings()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
yield return describe.Scoped<ICompositeValueProviderFactory, CompositeValueProviderFactory>();
|
yield return describe.Scoped<ICompositeValueProviderFactory, CompositeValueProviderFactory>();
|
||||||
yield return describe.Transient<IOutputFormattersProvider, DefaultOutputFormattersProvider>();
|
yield return describe.Transient<IOutputFormattersProvider, DefaultOutputFormattersProvider>();
|
||||||
|
|
||||||
yield return describe.Instance<JsonOutputFormatter>(
|
yield return describe.Instance<JsonOutputFormatter>(new JsonOutputFormatter());
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), indent: false));
|
|
||||||
|
|
||||||
yield return describe.Transient<IModelValidatorProviderProvider, DefaultModelValidatorProviderProvider>();
|
yield return describe.Transient<IModelValidatorProviderProvider, DefaultModelValidatorProviderProvider>();
|
||||||
yield return describe.Scoped<ICompositeModelValidatorProvider, CompositeModelValidatorProvider>();
|
yield return describe.Scoped<ICompositeModelValidatorProvider, CompositeModelValidatorProvider>();
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
result.Formatters = new List<IOutputFormatter>
|
result.Formatters = new List<IOutputFormatter>
|
||||||
{
|
{
|
||||||
new CannotWriteFormatter(),
|
new CannotWriteFormatter(),
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false),
|
new JsonOutputFormatter(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -170,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
result.Formatters = new List<IOutputFormatter>
|
result.Formatters = new List<IOutputFormatter>
|
||||||
{
|
{
|
||||||
new CannotWriteFormatter(),
|
new CannotWriteFormatter(),
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false),
|
new JsonOutputFormatter(),
|
||||||
};
|
};
|
||||||
// Act
|
// Act
|
||||||
await result.ExecuteResultAsync(actionContext);
|
await result.ExecuteResultAsync(actionContext);
|
||||||
|
|
@ -202,7 +202,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
result.Formatters = new List<IOutputFormatter>
|
result.Formatters = new List<IOutputFormatter>
|
||||||
{
|
{
|
||||||
mockFormatter.Object,
|
mockFormatter.Object,
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false),
|
new JsonOutputFormatter(),
|
||||||
new CannotWriteFormatter()
|
new CannotWriteFormatter()
|
||||||
};
|
};
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -232,7 +232,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
result.Formatters = new List<IOutputFormatter>
|
result.Formatters = new List<IOutputFormatter>
|
||||||
{
|
{
|
||||||
new CannotWriteFormatter(),
|
new CannotWriteFormatter(),
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false),
|
new JsonOutputFormatter(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -263,7 +263,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
result.Formatters = new List<IOutputFormatter>
|
result.Formatters = new List<IOutputFormatter>
|
||||||
{
|
{
|
||||||
new CannotWriteFormatter(),
|
new CannotWriteFormatter(),
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false),
|
new JsonOutputFormatter(),
|
||||||
};
|
};
|
||||||
// Act
|
// Act
|
||||||
await result.ExecuteResultAsync(actionContext);
|
await result.ExecuteResultAsync(actionContext);
|
||||||
|
|
@ -364,7 +364,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
result.Formatters = new List<IOutputFormatter>
|
result.Formatters = new List<IOutputFormatter>
|
||||||
{
|
{
|
||||||
new CannotWriteFormatter(),
|
new CannotWriteFormatter(),
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false),
|
new JsonOutputFormatter(),
|
||||||
};
|
};
|
||||||
// Act
|
// Act
|
||||||
await result.ExecuteResultAsync(actionContext);
|
await result.ExecuteResultAsync(actionContext);
|
||||||
|
|
@ -455,8 +455,8 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
Object = nonStringValue,
|
Object = nonStringValue,
|
||||||
DeclaredType = nonStringValue.GetType()
|
DeclaredType = nonStringValue.GetType()
|
||||||
};
|
};
|
||||||
var formatter = new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false);
|
var formatter = new JsonOutputFormatter();
|
||||||
formatter.WriteResponseContentHeaders(formatterContext);
|
formatter.WriteResponseHeaders(formatterContext);
|
||||||
await formatter.WriteAsync(formatterContext);
|
await formatter.WriteAsync(formatterContext);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -559,7 +559,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
|
||||||
return new List<IOutputFormatter>()
|
return new List<IOutputFormatter>()
|
||||||
{
|
{
|
||||||
new TextPlainFormatter(),
|
new TextPlainFormatter(),
|
||||||
new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), indent: false)
|
new JsonOutputFormatter()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1305,9 +1305,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
.Returns(
|
.Returns(
|
||||||
new List<IOutputFormatter>()
|
new List<IOutputFormatter>()
|
||||||
{
|
{
|
||||||
new JsonOutputFormatter(
|
new JsonOutputFormatter()
|
||||||
JsonOutputFormatter.CreateDefaultSettings(),
|
|
||||||
indent: false)
|
|
||||||
});
|
});
|
||||||
httpContext.SetupGet(o => o.Request.Accept)
|
httpContext.SetupGet(o => o.Request.Accept)
|
||||||
.Returns("");
|
.Returns("");
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#if ASPNET50
|
#if ASPNET50
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -11,12 +12,13 @@ using Microsoft.AspNet.Http;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class JsonInputFormatterTest
|
public class JsonInputFormatterTest
|
||||||
{
|
{
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("application/json", true)]
|
[InlineData("application/json", true)]
|
||||||
|
|
@ -64,7 +66,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
yield return new object[] { "100", typeof(int), 100 };
|
yield return new object[] { "100", typeof(int), 100 };
|
||||||
yield return new object[] { "'abcd'", typeof(string), "abcd" };
|
yield return new object[] { "'abcd'", typeof(string), "abcd" };
|
||||||
yield return new object[] { "'2012-02-01 12:45 AM'", typeof(DateTime),
|
yield return new object[] { "'2012-02-01 12:45 AM'", typeof(DateTime),
|
||||||
new DateTime(2012, 02, 01, 00, 45, 00) };
|
new DateTime(2012, 02, 01, 00, 45, 00) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -168,6 +170,72 @@ namespace Microsoft.AspNet.Mvc
|
||||||
Assert.IsType<TooManyModelErrorsException>(error.Exception);
|
Assert.IsType<TooManyModelErrorsException>(error.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Creates_SerializerSettings_ByDefault()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// Act
|
||||||
|
var jsonFormatter = new JsonInputFormatter();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(jsonFormatter.SerializerSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ChangesTo_DefaultSerializerSettings_TakesEffect()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// missing password property here
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("{ \"UserName\" : \"John\"}");
|
||||||
|
|
||||||
|
var jsonFormatter = new JsonInputFormatter() { CaptureDeserilizationErrors = true };
|
||||||
|
// by default we ignore missing members, so here explicitly changing it
|
||||||
|
jsonFormatter.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
|
||||||
|
|
||||||
|
var actionContext = GetActionContext(contentBytes, "application/json;charset=utf-8");
|
||||||
|
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(modelAccessor: null,
|
||||||
|
modelType: typeof(UserLogin));
|
||||||
|
var inputFormatterContext = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var obj = await jsonFormatter.ReadAsync(inputFormatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(actionContext.ModelState.IsValid);
|
||||||
|
|
||||||
|
var modelErrorMessage = actionContext.ModelState.Values.First().Errors[0].Exception.Message;
|
||||||
|
Assert.Contains("Required property 'Password' not found in JSON", modelErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CustomSerializerSettingsObject_TakesEffect()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// missing password property here
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("{ \"UserName\" : \"John\"}");
|
||||||
|
|
||||||
|
var jsonFormatter = new JsonInputFormatter() { CaptureDeserilizationErrors = true };
|
||||||
|
// by default we ignore missing members, so here explicitly changing it
|
||||||
|
jsonFormatter.SerializerSettings = new JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
MissingMemberHandling = MissingMemberHandling.Error
|
||||||
|
};
|
||||||
|
|
||||||
|
var actionContext = GetActionContext(contentBytes, "application/json;charset=utf-8");
|
||||||
|
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(modelAccessor: null,
|
||||||
|
modelType: typeof(UserLogin));
|
||||||
|
var inputFormatterContext = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var obj = await jsonFormatter.ReadAsync(inputFormatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(actionContext.ModelState.IsValid);
|
||||||
|
|
||||||
|
var modelErrorMessage = actionContext.ModelState.Values.First().Errors[0].Exception.Message;
|
||||||
|
Assert.Contains("Required property 'Password' not found in JSON", modelErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
private static ActionContext GetActionContext(byte[] contentBytes,
|
private static ActionContext GetActionContext(byte[] contentBytes,
|
||||||
string contentType = "application/xml")
|
string contentType = "application/xml")
|
||||||
{
|
{
|
||||||
|
|
@ -176,7 +244,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
new ActionDescriptor());
|
new ActionDescriptor());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpContext GetHttpContext(byte[] contentBytes,
|
private static HttpContext GetHttpContext(byte[] contentBytes,
|
||||||
string contentType = "application/json")
|
string contentType = "application/json")
|
||||||
{
|
{
|
||||||
var request = new Mock<HttpRequest>();
|
var request = new Mock<HttpRequest>();
|
||||||
|
|
@ -197,6 +265,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public decimal Age { get; set; }
|
public decimal Age { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class UserLogin
|
||||||
|
{
|
||||||
|
[JsonProperty(Required = Required.Always)]
|
||||||
|
public string UserName { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(Required = Required.Always)]
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
|
using Microsoft.AspNet.Routing;
|
||||||
|
using Moq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Core.Test.Formatters
|
||||||
|
{
|
||||||
|
public class JsonOutputFormatterTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Creates_SerializerSettings_ByDefault()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
// Act
|
||||||
|
var jsonFormatter = new JsonOutputFormatter();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(jsonFormatter.SerializerSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ChangesTo_DefaultSerializerSettings_TakesEffect()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var person = new User() { Name = "John", Age = 35 };
|
||||||
|
var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||||
|
Formatting = Formatting.Indented
|
||||||
|
});
|
||||||
|
|
||||||
|
var jsonFormatter = new JsonOutputFormatter();
|
||||||
|
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||||
|
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
|
||||||
|
var outputFormatterContext = GetOutputFormatterContext(person, typeof(User));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
|
||||||
|
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
|
||||||
|
Assert.Equal(expectedOutput,
|
||||||
|
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
|
||||||
|
.ReadToEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CustomSerializerSettingsObject_TakesEffect()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var person = new User() { Name = "John", Age = 35 };
|
||||||
|
var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||||
|
Formatting = Formatting.Indented
|
||||||
|
});
|
||||||
|
|
||||||
|
var jsonFormatter = new JsonOutputFormatter();
|
||||||
|
jsonFormatter.SerializerSettings = new JsonSerializerSettings()
|
||||||
|
{
|
||||||
|
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||||
|
Formatting = Formatting.Indented
|
||||||
|
};
|
||||||
|
|
||||||
|
var outputFormatterContext = GetOutputFormatterContext(person, typeof(User));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
|
||||||
|
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
|
||||||
|
|
||||||
|
var streamReader = new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8);
|
||||||
|
Assert.Equal(expectedOutput, streamReader.ReadToEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
private OutputFormatterContext GetOutputFormatterContext(object outputValue, Type outputType,
|
||||||
|
string contentType = "application/xml; charset=utf-8")
|
||||||
|
{
|
||||||
|
var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType);
|
||||||
|
|
||||||
|
return new OutputFormatterContext
|
||||||
|
{
|
||||||
|
Object = outputValue,
|
||||||
|
DeclaredType = outputType,
|
||||||
|
ActionContext = GetActionContext(mediaTypeHeaderValue),
|
||||||
|
SelectedEncoding = Encoding.GetEncoding(mediaTypeHeaderValue.Charset)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ActionContext GetActionContext(MediaTypeHeaderValue contentType)
|
||||||
|
{
|
||||||
|
var request = new Mock<HttpRequest>();
|
||||||
|
var headers = new Mock<IHeaderDictionary>();
|
||||||
|
request.Setup(r => r.ContentType).Returns(contentType.RawValue);
|
||||||
|
request.SetupGet(r => r.Headers).Returns(headers.Object);
|
||||||
|
request.SetupGet(f => f.AcceptCharset).Returns(contentType.Charset);
|
||||||
|
var response = new Mock<HttpResponse>();
|
||||||
|
response.SetupGet(f => f.Body).Returns(new MemoryStream());
|
||||||
|
var httpContext = new Mock<HttpContext>();
|
||||||
|
httpContext.SetupGet(c => c.Request).Returns(request.Object);
|
||||||
|
httpContext.SetupGet(c => c.Response).Returns(response.Object);
|
||||||
|
return new ActionContext(httpContext.Object, routeData: null, actionDescriptor: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class User
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public int Age { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -89,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var ex = Assert.Throws<InvalidOperationException>(
|
var ex = Assert.Throws<InvalidOperationException>(
|
||||||
() => testFormatter.WriteResponseContentHeaders(formatterContext));
|
() => testFormatter.WriteResponseHeaders(formatterContext));
|
||||||
Assert.Equal("No encoding found for output formatter " +
|
Assert.Equal("No encoding found for output formatter " +
|
||||||
"'Microsoft.AspNet.Mvc.Test.OutputFormatterTests+TestOutputFormatter'." +
|
"'Microsoft.AspNet.Mvc.Test.OutputFormatterTests+TestOutputFormatter'." +
|
||||||
" There must be at least one supported encoding registered in order for the" +
|
" There must be at least one supported encoding registered in order for the" +
|
||||||
|
|
@ -111,7 +111,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
formatterContext.ActionContext = actionContext;
|
formatterContext.ActionContext = actionContext;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
testFormatter.WriteResponseContentHeaders(formatterContext);
|
testFormatter.WriteResponseHeaders(formatterContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(Encodings.UTF16EncodingLittleEndian.WebName, formatterContext.SelectedEncoding.WebName);
|
Assert.Equal(Encodings.UTF16EncodingLittleEndian.WebName, formatterContext.SelectedEncoding.WebName);
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
private static readonly byte[] _abcdUTF8Bytes
|
private static readonly byte[] _abcdUTF8Bytes
|
||||||
= new byte[] { 123, 34, 102, 111, 111, 34, 58, 34, 97, 98, 99, 100, 34, 125 };
|
= new byte[] { 123, 34, 102, 111, 111, 34, 58, 34, 97, 98, 99, 100, 34, 125 };
|
||||||
private JsonOutputFormatter _jsonformatter = new JsonOutputFormatter(
|
|
||||||
JsonOutputFormatter.CreateDefaultSettings(),
|
|
||||||
indent: false);
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ExecuteResult_GeneratesResultsWithoutBOMByDefault()
|
public async Task ExecuteResult_GeneratesResultsWithoutBOMByDefault()
|
||||||
{
|
{
|
||||||
|
|
@ -95,7 +93,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
private HttpContext GetHttpContext(HttpResponse response, bool registerDefaultFormatter = true)
|
private HttpContext GetHttpContext(HttpResponse response, bool registerDefaultFormatter = true)
|
||||||
{
|
{
|
||||||
var defaultFormatters = registerDefaultFormatter ? new List<IOutputFormatter>() { _jsonformatter } :
|
var defaultFormatters = registerDefaultFormatter ? new List<IOutputFormatter>() { new JsonOutputFormatter() } :
|
||||||
new List<IOutputFormatter>();
|
new List<IOutputFormatter>();
|
||||||
var httpContext = new Mock<HttpContext>();
|
var httpContext = new Mock<HttpContext>();
|
||||||
var mockFormattersProvider = new Mock<IOutputFormattersProvider>();
|
var mockFormattersProvider = new Mock<IOutputFormattersProvider>();
|
||||||
|
|
@ -129,8 +127,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
// Override using the selected encoding.
|
// Override using the selected encoding.
|
||||||
context.SelectedEncoding = Encoding;
|
context.SelectedEncoding = Encoding;
|
||||||
var jsonFormatter = new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(),
|
var jsonFormatter = new JsonOutputFormatter();
|
||||||
indent: false);
|
|
||||||
await jsonFormatter.WriteResponseBodyAsync(context);
|
await jsonFormatter.WriteResponseBodyAsync(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ using System.Threading.Tasks;
|
||||||
using BasicWebSite;
|
using BasicWebSite;
|
||||||
using Microsoft.AspNet.Builder;
|
using Microsoft.AspNet.Builder;
|
||||||
using Microsoft.AspNet.TestHost;
|
using Microsoft.AspNet.TestHost;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
|
@ -186,6 +187,29 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task JsonViewComponent_RendersJson()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = new HttpClient(server.CreateHandler(), false);
|
||||||
|
var expectedBody = JsonConvert.SerializeObject(new BasicWebSite.Models.Person()
|
||||||
|
{
|
||||||
|
Id = 10,
|
||||||
|
Name = "John"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("https://localhost/Home/JsonTextInView");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("text/html", response.Content.Headers.ContentType.MediaType);
|
||||||
|
|
||||||
|
var actualBody = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal(expectedBody, actualBody);
|
||||||
|
}
|
||||||
|
|
||||||
public static IEnumerable<object[]> HtmlHelperLinkGenerationData
|
public static IEnumerable<object[]> HtmlHelperLinkGenerationData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||||
using ConnegWebsite;
|
using ConnegWebsite;
|
||||||
using Microsoft.AspNet.Builder;
|
using Microsoft.AspNet.Builder;
|
||||||
using Microsoft.AspNet.TestHost;
|
using Microsoft.AspNet.TestHost;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Builder;
|
||||||
|
using Microsoft.AspNet.TestHost;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
{
|
||||||
|
public class JsonOutputFormatterTests
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _provider = TestHelper.CreateServices("FormatterWebSite");
|
||||||
|
private readonly Action<IApplicationBuilder> _app = new FormatterWebSite.Startup().Configure;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task JsonOutputFormatter_ReturnsIndentedJson()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var user = new FormatterWebSite.User()
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Alias = "john",
|
||||||
|
description = "Administrator",
|
||||||
|
Designation = "Administrator",
|
||||||
|
Name = "John Williams"
|
||||||
|
};
|
||||||
|
|
||||||
|
var serializerSettings = new JsonSerializerSettings();
|
||||||
|
serializerSettings.Formatting = Formatting.Indented;
|
||||||
|
var expectedBody = JsonConvert.SerializeObject(user, serializerSettings);
|
||||||
|
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("http://localhost/JsonFormatter/ReturnsIndentedJson");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var actualBody = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal(expectedBody, actualBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,9 +28,7 @@ namespace ApiExplorer
|
||||||
typeof(ApiExplorerVisbilityDisabledByConventionController)));
|
typeof(ApiExplorerVisbilityDisabledByConventionController)));
|
||||||
|
|
||||||
options.OutputFormatters.Clear();
|
options.OutputFormatters.Clear();
|
||||||
options.OutputFormatters.Add(new JsonOutputFormatter(
|
options.OutputFormatters.Add(new JsonOutputFormatter());
|
||||||
JsonOutputFormatter.CreateDefaultSettings(),
|
|
||||||
indent: false));
|
|
||||||
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
|
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
using BasicWebSite.Models;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
|
namespace BasicWebSite.Components
|
||||||
|
{
|
||||||
|
[ViewComponent(Name = "JsonTextInView")]
|
||||||
|
public class JsonTextInView : ViewComponent
|
||||||
|
{
|
||||||
|
public IViewComponentResult Invoke()
|
||||||
|
{
|
||||||
|
return Json(new Person()
|
||||||
|
{
|
||||||
|
Id = 10,
|
||||||
|
Name = "John"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,5 +55,10 @@ namespace BasicWebSite.Controllers
|
||||||
Context.Response.StatusCode = 204;
|
Context.Response.StatusCode = 204;
|
||||||
await Context.Response.WriteAsync("Hello world");
|
await Context.Response.WriteAsync("Hello world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult JsonTextInView()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace BasicWebSite.Models
|
||||||
|
{
|
||||||
|
public class Person
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
@Component.Invoke("JsonTextInView")
|
||||||
|
|
@ -28,7 +28,7 @@ namespace ConnegWebsite
|
||||||
// JsonOutputFormatter cannot write in the first attempt because it does not support the
|
// JsonOutputFormatter cannot write in the first attempt because it does not support the
|
||||||
// request content type.
|
// request content type.
|
||||||
objectResult.Formatters.Add(new PlainTextFormatter());
|
objectResult.Formatters.Add(new PlainTextFormatter());
|
||||||
objectResult.Formatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false));
|
objectResult.Formatters.Add(new JsonOutputFormatter());
|
||||||
|
|
||||||
return objectResult;
|
return objectResult;
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ namespace ConnegWebsite
|
||||||
var objectResult = new ObjectResult(input);
|
var objectResult = new ObjectResult(input);
|
||||||
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
|
objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
|
||||||
objectResult.Formatters.Add(new PlainTextFormatter());
|
objectResult.Formatters.Add(new PlainTextFormatter());
|
||||||
objectResult.Formatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false));
|
objectResult.Formatters.Add(new JsonOutputFormatter());
|
||||||
return objectResult;
|
return objectResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
namespace ConnegWebsite
|
namespace ConnegWebsite
|
||||||
{
|
{
|
||||||
|
|
@ -15,8 +17,10 @@ namespace ConnegWebsite
|
||||||
{
|
{
|
||||||
result.Formatters.Add(new PlainTextFormatter());
|
result.Formatters.Add(new PlainTextFormatter());
|
||||||
result.Formatters.Add(new CustomFormatter("application/custom"));
|
result.Formatters.Add(new CustomFormatter("application/custom"));
|
||||||
result.Formatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(),
|
|
||||||
indent: true));
|
var jsonFormatter = new JsonOutputFormatter();
|
||||||
|
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
|
||||||
|
result.Formatters.Add(jsonFormatter);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnActionExecuted(context);
|
base.OnActionExecuted(context);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace FormatterWebSite.Controllers
|
||||||
|
{
|
||||||
|
public class JsonFormatterController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult ReturnsIndentedJson()
|
||||||
|
{
|
||||||
|
var user = new User()
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Alias = "john",
|
||||||
|
description = "Administrator",
|
||||||
|
Designation = "Administrator",
|
||||||
|
Name = "John Williams"
|
||||||
|
};
|
||||||
|
|
||||||
|
var jsonFormatter = new JsonOutputFormatter();
|
||||||
|
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
|
||||||
|
|
||||||
|
var objectResult = new ObjectResult(user);
|
||||||
|
objectResult.Formatters.Add(jsonFormatter);
|
||||||
|
|
||||||
|
return objectResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue