Fix #2330 - Reimagine *FormatterContext

This change simplifies InputFormatterContext/OutputFormatterContext by
swapping ActionContext for HttpContext.

This change is important especially for InputFormatterContext as it
decouples ModelState from ActionContext - allowing us to fix a
related bug where the _wrong_ ModelState can be passed in for a
TryUpdateModel operation.
This commit is contained in:
Ryan Nowak 2015-05-11 18:26:53 -07:00
parent fcf7b15c64
commit 39fe063aee
36 changed files with 402 additions and 370 deletions

View File

@ -2,33 +2,51 @@
// 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;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.Framework.Internal; using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
{ {
/// <summary> /// <summary>
/// Represents information used by an input formatter for /// A context object used by an input formatter for deserializing the request body into an object.
/// deserializing the request body into an object.
/// </summary> /// </summary>
public class InputFormatterContext public class InputFormatterContext
{ {
/// <summary> /// <summary>
/// Creates a new instance of <see cref="InputFormatterContext"/>. /// Creates a new instance of <see cref="InputFormatterContext"/>.
/// </summary> /// </summary>
public InputFormatterContext([NotNull] ActionContext actionContext, /// <param name="httpContext">
[NotNull] Type modelType) /// The <see cref="Http.HttpContext"/> for the current operation.
/// </param>
/// <param name="modelState">
/// The <see cref="ModelStateDictionary"/> for recording errors.
/// </param>
/// <param name="modelType">
/// The <see cref="Type"/> of the model to deserialize.
/// </param>
public InputFormatterContext(
[NotNull] HttpContext httpContext,
[NotNull] ModelStateDictionary modelState,
[NotNull] Type modelType)
{ {
ActionContext = actionContext; HttpContext = httpContext;
ModelState = modelState;
ModelType = modelType; ModelType = modelType;
} }
/// <summary> /// <summary>
/// Action context associated with the current call. /// Gets the <see cref="Http.HttpContext"/> associated with the current operation.
/// </summary> /// </summary>
public ActionContext ActionContext { get; private set; } public HttpContext HttpContext { get; private set; }
/// <summary> /// <summary>
/// Represents the expected type of the model represented by the request body. /// Gets the <see cref="ModelStateDictionary"/> associated with the current operation.
/// </summary>
public ModelStateDictionary ModelState { get; }
/// <summary>
/// Gets the expected <see cref="Type"/> of the model represented by the request body.
/// </summary> /// </summary>
public Type ModelType { get; private set; } public Type ModelType { get; private set; }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using System.Text; using System.Text;
using Microsoft.AspNet.Http;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNet.Mvc namespace Microsoft.AspNet.Mvc
@ -24,9 +25,9 @@ namespace Microsoft.AspNet.Mvc
public Type DeclaredType { get; set; } public Type DeclaredType { get; set; }
/// <summary> /// <summary>
/// Action context associated with the current call. /// Gets or sets the <see cref="HttpContext"/> context associated with the current operation.
/// </summary> /// </summary>
public ActionContext ActionContext { get; set; } public HttpContext HttpContext { get; set; }
/// <summary> /// <summary>
/// The encoding which is chosen by the selected formatter. /// The encoding which is chosen by the selected formatter.

View File

@ -101,7 +101,7 @@ namespace Microsoft.AspNet.Mvc
var formatterContext = new OutputFormatterContext() var formatterContext = new OutputFormatterContext()
{ {
ActionContext = context, HttpContext = context.HttpContext,
DeclaredType = objectResult.DeclaredType, DeclaredType = objectResult.DeclaredType,
Object = Value, Object = Value,
}; };
@ -125,7 +125,6 @@ namespace Microsoft.AspNet.Mvc
{ {
// If no formatter was provided, then run Conneg with the formatters configured in options. // If no formatter was provided, then run Conneg with the formatters configured in options.
var formatters = formatterContext var formatters = formatterContext
.ActionContext
.HttpContext .HttpContext
.RequestServices .RequestServices
.GetRequiredService<IOptions<MvcOptions>>() .GetRequiredService<IOptions<MvcOptions>>()
@ -140,7 +139,6 @@ namespace Microsoft.AspNet.Mvc
// If the available user-configured formatters can't write this type, then fall back to the // If the available user-configured formatters can't write this type, then fall back to the
// 'global' one. // 'global' one.
formatter = formatterContext formatter = formatterContext
.ActionContext
.HttpContext .HttpContext
.RequestServices .RequestServices
.GetRequiredService<JsonOutputFormatter>(); .GetRequiredService<JsonOutputFormatter>();

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Mvc
var formatterContext = new OutputFormatterContext() var formatterContext = new OutputFormatterContext()
{ {
DeclaredType = DeclaredType, DeclaredType = DeclaredType,
ActionContext = context, HttpContext = context.HttpContext,
Object = Value, Object = Value,
StatusCode = StatusCode StatusCode = StatusCode
}; };
@ -83,8 +83,7 @@ namespace Microsoft.AspNet.Mvc
OutputFormatterContext formatterContext, OutputFormatterContext formatterContext,
IEnumerable<IOutputFormatter> formatters) IEnumerable<IOutputFormatter> formatters)
{ {
var logger = formatterContext.ActionContext.HttpContext.RequestServices var logger = formatterContext.HttpContext.RequestServices.GetRequiredService<ILogger<ObjectResult>>();
.GetRequiredService<ILogger<ObjectResult>>();
// Check if any content-type was explicitly set (for example, via ProducesAttribute // Check if any content-type was explicitly set (for example, via ProducesAttribute
// or Url path extension mapping). If yes, then ignore content-negotiation and use this content-type. // or Url path extension mapping). If yes, then ignore content-negotiation and use this content-type.
@ -108,7 +107,7 @@ namespace Microsoft.AspNet.Mvc
// which can write the type. // which can write the type.
MediaTypeHeaderValue requestContentType = null; MediaTypeHeaderValue requestContentType = null;
MediaTypeHeaderValue.TryParse( MediaTypeHeaderValue.TryParse(
formatterContext.ActionContext.HttpContext.Request.ContentType, formatterContext.HttpContext.Request.ContentType,
out requestContentType); out requestContentType);
if (!sortedAcceptHeaderMediaTypes.Any() && requestContentType == null) if (!sortedAcceptHeaderMediaTypes.Any() && requestContentType == null)
{ {
@ -240,17 +239,18 @@ namespace Microsoft.AspNet.Mvc
private IEnumerable<MediaTypeHeaderValue> GetSortedAcceptHeaderMediaTypes( private IEnumerable<MediaTypeHeaderValue> GetSortedAcceptHeaderMediaTypes(
OutputFormatterContext formatterContext) OutputFormatterContext formatterContext)
{ {
var request = formatterContext.ActionContext.HttpContext.Request; var request = formatterContext.HttpContext.Request;
var incomingAcceptHeaderMediaTypes = request.GetTypedHeaders().Accept ?? new MediaTypeHeaderValue[] { }; var incomingAcceptHeaderMediaTypes = request.GetTypedHeaders().Accept ?? new MediaTypeHeaderValue[] { };
// By default we want to ignore considering accept headers for content negotiation when // By default we want to ignore considering accept headers for content negotiation when
// they have a media type like */* in them. Browsers typically have these media types. // they have a media type like */* in them. Browsers typically have these media types.
// In these cases we would want the first formatter in the list of output formatters to // In these cases we would want the first formatter in the list of output formatters to
// write the response. This default behavior can be changed through options, so checking here. // write the response. This default behavior can be changed through options, so checking here.
var options = formatterContext.ActionContext.HttpContext var options = formatterContext
.RequestServices .HttpContext
.GetRequiredService<IOptions<MvcOptions>>() .RequestServices
.Options; .GetRequiredService<IOptions<MvcOptions>>()
.Options;
var respectAcceptHeader = true; var respectAcceptHeader = true;
if (options.RespectBrowserAcceptHeader == false if (options.RespectBrowserAcceptHeader == false

View File

@ -33,7 +33,7 @@ namespace Microsoft.AspNet.Mvc
public Task WriteAsync(OutputFormatterContext context) public Task WriteAsync(OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
response.ContentLength = 0; response.ContentLength = 0;
response.StatusCode = context.StatusCode ?? StatusCodes.Status204NoContent; response.StatusCode = context.StatusCode ?? StatusCodes.Status204NoContent;
return Task.FromResult(true); return Task.FromResult(true);

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Mvc
/// <inheritdoc /> /// <inheritdoc />
public Task WriteAsync(OutputFormatterContext context) public Task WriteAsync(OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
response.StatusCode = StatusCodes.Status406NotAcceptable; response.StatusCode = StatusCodes.Status406NotAcceptable;
return Task.FromResult(true); return Task.FromResult(true);
} }

View File

@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Mvc
return false; return false;
} }
var contentType = context.ActionContext.HttpContext.Request.ContentType; var contentType = context.HttpContext.Request.ContentType;
MediaTypeHeaderValue requestContentType; MediaTypeHeaderValue requestContentType;
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType)) if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
{ {
@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Mvc
/// <inheritdoc /> /// <inheritdoc />
public virtual async Task<object> ReadAsync(InputFormatterContext context) public virtual async Task<object> ReadAsync(InputFormatterContext context)
{ {
var request = context.ActionContext.HttpContext.Request; var request = context.HttpContext.Request;
if (request.ContentLength == 0) if (request.ContentLength == 0)
{ {
return GetDefaultValueForType(context.ModelType); return GetDefaultValueForType(context.ModelType);

View File

@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Mvc
public override Task<object> ReadRequestBodyAsync([NotNull] InputFormatterContext context) public override Task<object> ReadRequestBodyAsync([NotNull] InputFormatterContext context)
{ {
var type = context.ModelType; var type = context.ModelType;
var request = context.ActionContext.HttpContext.Request; var request = context.HttpContext.Request;
MediaTypeHeaderValue requestContentType = null; MediaTypeHeaderValue requestContentType = null;
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType); MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);
@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Mvc
errorHandler = (sender, e) => errorHandler = (sender, e) =>
{ {
var exception = e.ErrorContext.Error; var exception = e.ErrorContext.Error;
context.ActionContext.ModelState.TryAddModelError(e.ErrorContext.Path, e.ErrorContext.Error); context.ModelState.TryAddModelError(e.ErrorContext.Path, e.ErrorContext.Error);
// Error must always be marked as handled // Error must always be marked as handled
// Failure to do so can cause the exception to be rethrown at every recursive level and // Failure to do so can cause the exception to be rethrown at every recursive level and

View File

@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Mvc
public override Task WriteResponseBodyAsync(OutputFormatterContext context) public override Task WriteResponseBodyAsync(OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
var selectedEncoding = context.SelectedEncoding; var selectedEncoding = context.SelectedEncoding;
using (var writer = new HttpResponseStreamWriter(response.Body, selectedEncoding)) using (var writer = new HttpResponseStreamWriter(response.Body, selectedEncoding))

View File

@ -104,7 +104,7 @@ namespace Microsoft.AspNet.Mvc
/// <returns>The <see cref="Encoding"/> to use when reading the request or writing the response.</returns> /// <returns>The <see cref="Encoding"/> to use when reading the request or writing the response.</returns>
public virtual Encoding SelectCharacterEncoding([NotNull] OutputFormatterContext context) public virtual Encoding SelectCharacterEncoding([NotNull] OutputFormatterContext context)
{ {
var request = context.ActionContext.HttpContext.Request; var request = context.HttpContext.Request;
var encoding = MatchAcceptCharacterEncoding(request.GetTypedHeaders().AcceptCharset); var encoding = MatchAcceptCharacterEncoding(request.GetTypedHeaders().AcceptCharset);
if (encoding == null) if (encoding == null)
{ {
@ -195,7 +195,7 @@ namespace Microsoft.AspNet.Mvc
selectedMediaType.Charset = selectedEncoding.WebName; selectedMediaType.Charset = selectedEncoding.WebName;
context.SelectedContentType = context.SelectedContentType ?? selectedMediaType; context.SelectedContentType = context.SelectedContentType ?? selectedMediaType;
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
response.ContentType = selectedMediaType.ToString(); response.ContentType = selectedMediaType.ToString();
} }

View File

@ -33,7 +33,7 @@ namespace Microsoft.AspNet.Mvc
{ {
using (var valueAsStream = ((Stream)context.Object)) using (var valueAsStream = ((Stream)context.Object))
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
if (context.SelectedContentType != null) if (context.SelectedContentType != null)
{ {

View File

@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Mvc
return; return;
} }
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
await response.WriteAsync(valueAsString, context.SelectedEncoding); await response.WriteAsync(valueAsString, context.SelectedEncoding);
} }

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection;
@ -26,14 +25,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
} }
/// <inheritdoc /> /// <inheritdoc />
protected async override Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext) protected async override Task<ModelBindingResult> BindModelCoreAsync(
[NotNull] ModelBindingContext bindingContext)
{ {
var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices; var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
var actionContext = requestServices.GetRequiredService<IScopedInstance<ActionContext>>().Value; var httpContext = bindingContext.OperationBindingContext.HttpContext;
var formatters = requestServices.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value.InputFormatters; var formatters = requestServices
.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value.InputFormatters;
var formatterContext = new InputFormatterContext(actionContext, bindingContext.ModelType); var formatterContext = new InputFormatterContext(
httpContext,
bindingContext.ModelState,
bindingContext.ModelType);
var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext)); var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext));
if (formatter == null) if (formatter == null)

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
public async Task WriteAsync(OutputFormatterContext context) public async Task WriteAsync(OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
var responseMessage = context.Object as HttpResponseMessage; var responseMessage = context.Object as HttpResponseMessage;
if (responseMessage == null) if (responseMessage == null)
@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
{ {
response.StatusCode = (int)responseMessage.StatusCode; response.StatusCode = (int)responseMessage.StatusCode;
var responseFeature = context.ActionContext.HttpContext.GetFeature<IHttpResponseFeature>(); var responseFeature = context.HttpContext.GetFeature<IHttpResponseFeature>();
if (responseFeature != null) if (responseFeature != null)
{ {
responseFeature.ReasonPhrase = responseMessage.ReasonPhrase; responseFeature.ReasonPhrase = responseMessage.ReasonPhrase;

View File

@ -94,7 +94,7 @@ namespace Microsoft.AspNet.Mvc.Xml
/// <returns>Task which reads the input.</returns> /// <returns>Task which reads the input.</returns>
public override Task<object> ReadRequestBodyAsync(InputFormatterContext context) public override Task<object> ReadRequestBodyAsync(InputFormatterContext context)
{ {
var request = context.ActionContext.HttpContext.Request; var request = context.HttpContext.Request;
MediaTypeHeaderValue requestContentType; MediaTypeHeaderValue requestContentType;
MediaTypeHeaderValue.TryParse(request.ContentType , out requestContentType); MediaTypeHeaderValue.TryParse(request.ContentType , out requestContentType);
@ -106,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.Xml
_dataAnnotationRequiredAttributeValidation.Validate( _dataAnnotationRequiredAttributeValidation.Validate(
type, type,
context.ActionContext.ModelState); context.ModelState);
var serializer = GetCachedSerializer(type); var serializer = GetCachedSerializer(type);

View File

@ -167,7 +167,7 @@ namespace Microsoft.AspNet.Mvc.Xml
var tempWriterSettings = WriterSettings.Clone(); var tempWriterSettings = WriterSettings.Clone();
tempWriterSettings.Encoding = context.SelectedEncoding; tempWriterSettings.Encoding = context.SelectedEncoding;
var innerStream = context.ActionContext.HttpContext.Response.Body; var innerStream = context.HttpContext.Response.Body;
using (var outputStream = new NonDisposableStream(innerStream)) using (var outputStream = new NonDisposableStream(innerStream))
using (var xmlWriter = CreateXmlWriter(outputStream, tempWriterSettings)) using (var xmlWriter = CreateXmlWriter(outputStream, tempWriterSettings))

View File

@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.Xml
/// <returns>Task which reads the input.</returns> /// <returns>Task which reads the input.</returns>
public override Task<object> ReadRequestBodyAsync(InputFormatterContext context) public override Task<object> ReadRequestBodyAsync(InputFormatterContext context)
{ {
var request = context.ActionContext.HttpContext.Request; var request = context.HttpContext.Request;
MediaTypeHeaderValue requestContentType; MediaTypeHeaderValue requestContentType;
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType); MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);

View File

@ -139,12 +139,12 @@ namespace Microsoft.AspNet.Mvc.Xml
/// <inheritdoc /> /// <inheritdoc />
public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context) public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
var tempWriterSettings = WriterSettings.Clone(); var tempWriterSettings = WriterSettings.Clone();
tempWriterSettings.Encoding = context.SelectedEncoding; tempWriterSettings.Encoding = context.SelectedEncoding;
var innerStream = context.ActionContext.HttpContext.Response.Body; var innerStream = context.HttpContext.Response.Body;
using (var outputStream = new NonDisposableStream(innerStream)) using (var outputStream = new NonDisposableStream(innerStream))
using (var xmlWriter = CreateXmlWriter(outputStream, tempWriterSettings)) using (var xmlWriter = CreateXmlWriter(outputStream, tempWriterSettings))

View File

@ -357,7 +357,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
var context = new OutputFormatterContext() var context = new OutputFormatterContext()
{ {
ActionContext = actionContext, HttpContext = actionContext.HttpContext,
Object = input, Object = input,
DeclaredType = typeof(string) DeclaredType = typeof(string)
}; };
@ -530,7 +530,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
new ActionDescriptor()); new ActionDescriptor());
var formatterContext = new OutputFormatterContext() var formatterContext = new OutputFormatterContext()
{ {
ActionContext = tempActionContext, HttpContext = tempActionContext.HttpContext,
Object = nonStringValue, Object = nonStringValue,
DeclaredType = nonStringValue.GetType() DeclaredType = nonStringValue.GetType()
}; };

View File

@ -38,8 +38,8 @@ namespace Microsoft.AspNet.Mvc
var formatter = new JsonInputFormatter(); var formatter = new JsonInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes("content"); var contentBytes = Encoding.UTF8.GetBytes("content");
var actionContext = GetActionContext(contentBytes, contentType: requestContentType); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType);
var formatterContext = new InputFormatterContext(actionContext, typeof(string)); var formatterContext = new InputFormatterContext(httpContext, new ModelStateDictionary(), typeof(string));
// Act // Act
var result = formatter.CanRead(formatterContext); var result = formatter.CanRead(formatterContext);
@ -80,8 +80,8 @@ namespace Microsoft.AspNet.Mvc
var formatter = new JsonInputFormatter(); var formatter = new JsonInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes); var httpContext = GetHttpContext(contentBytes);
var context = new InputFormatterContext(actionContext, type); var context = new InputFormatterContext(httpContext, new ModelStateDictionary(), type);
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
@ -98,9 +98,8 @@ namespace Microsoft.AspNet.Mvc
var formatter = new JsonInputFormatter(); var formatter = new JsonInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes); var httpContext = GetHttpContext(contentBytes);
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(User)); var context = new InputFormatterContext(httpContext, new ModelStateDictionary(), typeof(User));
var context = new InputFormatterContext(actionContext, metadata.ModelType);
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
@ -119,16 +118,18 @@ namespace Microsoft.AspNet.Mvc
var formatter = new JsonInputFormatter(); var formatter = new JsonInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes); var modelState = new ModelStateDictionary();
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(User)); var httpContext = GetHttpContext(contentBytes);
var context = new InputFormatterContext(actionContext, metadata.ModelType);
var context = new InputFormatterContext(httpContext, modelState, typeof(User));
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
// Assert // Assert
Assert.Equal("Could not convert string to decimal: not-an-age. Path 'Age', line 1, position 39.", Assert.Equal(
actionContext.ModelState["Age"].Errors[0].Exception.Message); "Could not convert string to decimal: not-an-age. Path 'Age', line 1, position 39.",
modelState["Age"].Errors[0].Exception.Message);
} }
[Fact] [Fact]
@ -139,19 +140,21 @@ namespace Microsoft.AspNet.Mvc
var formatter = new JsonInputFormatter(); var formatter = new JsonInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes); var modelState = new ModelStateDictionary();
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(User)); var httpContext = GetHttpContext(contentBytes);
var context = new InputFormatterContext(actionContext, metadata.ModelType);
actionContext.ModelState.MaxAllowedErrors = 3; var context = new InputFormatterContext(httpContext, modelState, typeof(User));
actionContext.ModelState.AddModelError("key1", "error1");
actionContext.ModelState.AddModelError("key2", "error2"); modelState.MaxAllowedErrors = 3;
modelState.AddModelError("key1", "error1");
modelState.AddModelError("key2", "error2");
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
// Assert // Assert
Assert.False(actionContext.ModelState.ContainsKey("age")); Assert.False(modelState.ContainsKey("age"));
var error = Assert.Single(actionContext.ModelState[""].Errors); var error = Assert.Single(modelState[""].Errors);
Assert.IsType<TooManyModelErrorsException>(error.Exception); Assert.IsType<TooManyModelErrorsException>(error.Exception);
} }
@ -189,17 +192,18 @@ namespace Microsoft.AspNet.Mvc
// by default we ignore missing members, so here explicitly changing it // by default we ignore missing members, so here explicitly changing it
jsonFormatter.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error; jsonFormatter.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Error;
var actionContext = GetActionContext(contentBytes, "application/json;charset=utf-8"); var modelState = new ModelStateDictionary();
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(UserLogin)); var httpContext = GetHttpContext(contentBytes, "application/json;charset=utf-8");
var inputFormatterContext = new InputFormatterContext(actionContext, metadata.ModelType);
var inputFormatterContext = new InputFormatterContext(httpContext, modelState, typeof(UserLogin));
// Act // Act
var obj = await jsonFormatter.ReadAsync(inputFormatterContext); var obj = await jsonFormatter.ReadAsync(inputFormatterContext);
// Assert // Assert
Assert.False(actionContext.ModelState.IsValid); Assert.False(modelState.IsValid);
var modelErrorMessage = actionContext.ModelState.Values.First().Errors[0].Exception.Message; var modelErrorMessage = modelState.Values.First().Errors[0].Exception.Message;
Assert.Contains("Required property 'Password' not found in JSON", modelErrorMessage); Assert.Contains("Required property 'Password' not found in JSON", modelErrorMessage);
} }
@ -217,51 +221,24 @@ namespace Microsoft.AspNet.Mvc
MissingMemberHandling = MissingMemberHandling.Error MissingMemberHandling = MissingMemberHandling.Error
}; };
var actionContext = GetActionContext(contentBytes, "application/json;charset=utf-8"); var modelState = new ModelStateDictionary();
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(UserLogin)); var httpContext = GetHttpContext(contentBytes, "application/json;charset=utf-8");
var inputFormatterContext = new InputFormatterContext(actionContext, metadata.ModelType);
var inputFormatterContext = new InputFormatterContext(httpContext, modelState, typeof(UserLogin));
// Act // Act
var obj = await jsonFormatter.ReadAsync(inputFormatterContext); var obj = await jsonFormatter.ReadAsync(inputFormatterContext);
// Assert // Assert
Assert.False(actionContext.ModelState.IsValid); Assert.False(modelState.IsValid);
var modelErrorMessage = actionContext.ModelState.Values.First().Errors[0].Exception.Message; var modelErrorMessage = modelState.Values.First().Errors[0].Exception.Message;
Assert.Contains("Required property 'Password' not found in JSON", modelErrorMessage); Assert.Contains("Required property 'Password' not found in JSON", modelErrorMessage);
} }
[Fact] private static HttpContext GetHttpContext(
public async Task Validation_DoesNotHappen_ForNonRequired_ValueTypeProperties() byte[] contentBytes,
{ string contentType = "application/json")
// Arrange
var contentBytes = Encoding.UTF8.GetBytes("{\"Name\":\"Seattle\"}");
var jsonFormatter = new JsonInputFormatter();
var actionContext = GetActionContext(contentBytes, "application/json;charset=utf-8");
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(Location));
var inputFormatterContext = new InputFormatterContext(actionContext, metadata.ModelType);
// Act
var obj = await jsonFormatter.ReadAsync(inputFormatterContext);
// Assert
Assert.True(actionContext.ModelState.IsValid);
var location = obj as Location;
Assert.NotNull(location);
Assert.Equal(0, location.Id);
Assert.Equal("Seattle", location.Name);
}
private static ActionContext GetActionContext(byte[] contentBytes,
string contentType = "application/xml")
{
return new ActionContext(GetHttpContext(contentBytes, contentType),
new AspNet.Routing.RouteData(),
new ActionDescriptor());
}
private static HttpContext GetHttpContext(byte[] contentBytes,
string contentType = "application/json")
{ {
var request = new Mock<HttpRequest>(); var request = new Mock<HttpRequest>();
var headers = new Mock<IHeaderDictionary>(); var headers = new Mock<IHeaderDictionary>();

View File

@ -62,11 +62,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test.Formatters
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext); await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
Assert.Equal(expectedOutput, Assert.NotNull(body);
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8) body.Position = 0;
.ReadToEnd());
var content = new StreamReader(body, Encoding.UTF8).ReadToEnd();
Assert.Equal(expectedOutput, content);
} }
[Fact] [Fact]
@ -93,11 +95,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test.Formatters
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext); await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
var streamReader = new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8); Assert.NotNull(body);
Assert.Equal(expectedOutput, streamReader.ReadToEnd()); body.Position = 0;
var content = new StreamReader(body, Encoding.UTF8).ReadToEnd();
Assert.Equal(expectedOutput, content);
} }
[Fact] [Fact]
@ -155,12 +159,14 @@ namespace Microsoft.AspNet.Mvc.Core.Test.Formatters
var encoding = CreateOrGetSupportedEncoding(formatter, encodingAsString, isDefaultEncoding); var encoding = CreateOrGetSupportedEncoding(formatter, encodingAsString, isDefaultEncoding);
var expectedData = encoding.GetBytes(formattedContent); var expectedData = encoding.GetBytes(formattedContent);
var memStream = new MemoryStream();
var body = new MemoryStream();
var actionContext = GetActionContext(MediaTypeHeaderValue.Parse(mediaType), body);
var outputFormatterContext = new OutputFormatterContext var outputFormatterContext = new OutputFormatterContext
{ {
Object = content, Object = content,
DeclaredType = typeof(string), DeclaredType = typeof(string),
ActionContext = GetActionContext(MediaTypeHeaderValue.Parse(mediaType), memStream), HttpContext = actionContext.HttpContext,
SelectedEncoding = encoding SelectedEncoding = encoding
}; };
@ -168,7 +174,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.Formatters
await formatter.WriteResponseBodyAsync(outputFormatterContext); await formatter.WriteResponseBodyAsync(outputFormatterContext);
// Assert // Assert
var actualData = memStream.ToArray(); var actualData = body.ToArray();
Assert.Equal(expectedData, actualData); Assert.Equal(expectedData, actualData);
} }
@ -200,11 +206,12 @@ namespace Microsoft.AspNet.Mvc.Core.Test.Formatters
{ {
var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType); var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType);
var actionContext = GetActionContext(mediaTypeHeaderValue, responseStream);
return new OutputFormatterContext return new OutputFormatterContext
{ {
Object = outputValue, Object = outputValue,
DeclaredType = outputType, DeclaredType = outputType,
ActionContext = GetActionContext(mediaTypeHeaderValue, responseStream), HttpContext = actionContext.HttpContext,
SelectedEncoding = Encoding.GetEncoding(mediaTypeHeaderValue.Charset) SelectedEncoding = Encoding.GetEncoding(mediaTypeHeaderValue.Charset)
}; };
} }

View File

@ -23,8 +23,9 @@ namespace Microsoft.AspNet.Mvc
var content = "[{\"op\":\"add\",\"path\":\"Customer/Name\",\"value\":\"John\"}]"; var content = "[{\"op\":\"add\",\"path\":\"Customer/Name\",\"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes); var modelState = new ModelStateDictionary();
var context = new InputFormatterContext(actionContext, typeof(JsonPatchDocument<Customer>)); var httpContext = GetHttpContext(contentBytes);
var context = new InputFormatterContext(httpContext, modelState, typeof(JsonPatchDocument<Customer>));
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
@ -45,8 +46,9 @@ namespace Microsoft.AspNet.Mvc
"{\"op\": \"remove\", \"path\" : \"Customer/Name\"}]"; "{\"op\": \"remove\", \"path\" : \"Customer/Name\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes); var modelState = new ModelStateDictionary();
var context = new InputFormatterContext(actionContext, typeof(JsonPatchDocument<Customer>)); var httpContext = GetHttpContext(contentBytes);
var context = new InputFormatterContext(httpContext, modelState, typeof(JsonPatchDocument<Customer>));
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
@ -72,8 +74,12 @@ namespace Microsoft.AspNet.Mvc
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes, contentType: requestContentType); var modelState = new ModelStateDictionary();
var formatterContext = new InputFormatterContext(actionContext, typeof(JsonPatchDocument<Customer>)); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType);
var formatterContext = new InputFormatterContext(
httpContext,
modelState,
typeof(JsonPatchDocument<Customer>));
// Act // Act
var result = formatter.CanRead(formatterContext); var result = formatter.CanRead(formatterContext);
@ -92,8 +98,9 @@ namespace Microsoft.AspNet.Mvc
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes, contentType: "application/json-patch+json"); var modelState = new ModelStateDictionary();
var formatterContext = new InputFormatterContext(actionContext, modelType); var httpContext = GetHttpContext(contentBytes, contentType: "application/json-patch+json");
var formatterContext = new InputFormatterContext(httpContext, modelState, modelType);
// Act // Act
var result = formatter.CanRead(formatterContext); var result = formatter.CanRead(formatterContext);
@ -113,25 +120,20 @@ namespace Microsoft.AspNet.Mvc
var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]"; var content = "[{\"op\": \"add\", \"path\" : \"Customer/Name\", \"value\":\"John\"}]";
var contentBytes = Encoding.UTF8.GetBytes(content); var contentBytes = Encoding.UTF8.GetBytes(content);
var actionContext = GetActionContext(contentBytes, contentType: "application/json-patch+json"); var modelState = new ModelStateDictionary();
var context = new InputFormatterContext(actionContext, typeof(Customer)); var httpContext = GetHttpContext(contentBytes, contentType: "application/json-patch+json");
var context = new InputFormatterContext(httpContext, modelState, typeof(Customer));
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
// Assert // Assert
Assert.Contains(exceptionMessage, actionContext.ModelState[""].Errors[0].Exception.Message); Assert.Contains(exceptionMessage, modelState[""].Errors[0].Exception.Message);
} }
private static ActionContext GetActionContext(byte[] contentBytes, private static HttpContext GetHttpContext(
string contentType = "application/json-patch+json") byte[] contentBytes,
{
return new ActionContext(GetHttpContext(contentBytes, contentType),
new AspNet.Routing.RouteData(),
new ActionDescriptor());
}
private static HttpContext GetHttpContext(byte[] contentBytes,
string contentType = "application/json-patch+json") string contentType = "application/json-patch+json")
{ {
var request = new Mock<HttpRequest>(); var request = new Mock<HttpRequest>();

View File

@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.Test
{ {
Object = value, Object = value,
DeclaredType = typeToUse, DeclaredType = typeToUse,
ActionContext = null, HttpContext = null,
}; };
var contetType = useNonNullContentType ? MediaTypeHeaderValue.Parse("text/plain") : null; var contetType = useNonNullContentType ? MediaTypeHeaderValue.Parse("text/plain") : null;
var formatter = new HttpNoContentOutputFormatter(); var formatter = new HttpNoContentOutputFormatter();
@ -67,7 +67,7 @@ namespace Microsoft.AspNet.Mvc.Test
{ {
Object = "Something non null.", Object = "Something non null.",
DeclaredType = declaredType, DeclaredType = declaredType,
ActionContext = null, HttpContext = null,
}; };
var contetType = MediaTypeHeaderValue.Parse("text/plain"); var contetType = MediaTypeHeaderValue.Parse("text/plain");
var formatter = new HttpNoContentOutputFormatter(); var formatter = new HttpNoContentOutputFormatter();
@ -93,7 +93,7 @@ namespace Microsoft.AspNet.Mvc.Test
{ {
Object = value, Object = value,
DeclaredType = typeof(string), DeclaredType = typeof(string),
ActionContext = null, HttpContext = null,
}; };
var contetType = MediaTypeHeaderValue.Parse("text/plain"); var contetType = MediaTypeHeaderValue.Parse("text/plain");
@ -117,7 +117,7 @@ namespace Microsoft.AspNet.Mvc.Test
var formatterContext = new OutputFormatterContext() var formatterContext = new OutputFormatterContext()
{ {
Object = null, Object = null,
ActionContext = new ActionContext(defaultHttpContext, new RouteData(), new ActionDescriptor()) HttpContext = defaultHttpContext,
}; };
var formatter = new HttpNoContentOutputFormatter(); var formatter = new HttpNoContentOutputFormatter();
@ -137,7 +137,7 @@ namespace Microsoft.AspNet.Mvc.Test
var formatterContext = new OutputFormatterContext() var formatterContext = new OutputFormatterContext()
{ {
Object = null, Object = null,
ActionContext = new ActionContext(defaultHttpContext, new RouteData(), new ActionDescriptor()), HttpContext = defaultHttpContext,
StatusCode = StatusCodes.Status201Created StatusCode = StatusCodes.Status201Created
}; };

View File

@ -54,7 +54,7 @@ namespace Microsoft.AspNet.Mvc.Test
httpRequest.Headers["Accept-Charset"] = acceptCharsetHeaders; httpRequest.Headers["Accept-Charset"] = acceptCharsetHeaders;
httpRequest.ContentType = "application/acceptCharset;charset=" + requestEncoding; httpRequest.ContentType = "application/acceptCharset;charset=" + requestEncoding;
mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest); mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest);
var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor());
var formatter = new TestOutputFormatter(); var formatter = new TestOutputFormatter();
foreach (string supportedEncoding in supportedEncodings) foreach (string supportedEncoding in supportedEncodings)
{ {
@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc.Test
var formatterContext = new OutputFormatterContext() var formatterContext = new OutputFormatterContext()
{ {
Object = "someValue", Object = "someValue",
ActionContext = actionContext, HttpContext = mockHttpContext.Object,
DeclaredType = typeof(string) DeclaredType = typeof(string)
}; };
@ -85,8 +85,7 @@ namespace Microsoft.AspNet.Mvc.Test
var mockHttpContext = new Mock<HttpContext>(); var mockHttpContext = new Mock<HttpContext>();
var httpRequest = new DefaultHttpContext().Request; var httpRequest = new DefaultHttpContext().Request;
mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest); mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest);
var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor()); formatterContext.HttpContext = mockHttpContext.Object;
formatterContext.ActionContext = actionContext;
// Act & Assert // Act & Assert
var ex = Assert.Throws<InvalidOperationException>( var ex = Assert.Throws<InvalidOperationException>(
@ -108,8 +107,7 @@ namespace Microsoft.AspNet.Mvc.Test
var httpRequest = new DefaultHttpContext().Request; var httpRequest = new DefaultHttpContext().Request;
mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest); mockHttpContext.SetupGet(o => o.Request).Returns(httpRequest);
mockHttpContext.SetupProperty(o => o.Response.ContentType); mockHttpContext.SetupProperty(o => o.Response.ContentType);
var actionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor()); formatterContext.HttpContext = mockHttpContext.Object;
formatterContext.ActionContext = actionContext;
// Act // Act
testFormatter.WriteResponseHeaders(formatterContext); testFormatter.WriteResponseHeaders(formatterContext);
@ -130,10 +128,7 @@ namespace Microsoft.AspNet.Mvc.Test
var mediaType = new MediaTypeHeaderValue("image/png"); var mediaType = new MediaTypeHeaderValue("image/png");
formatter.SupportedMediaTypes.Add(mediaType); formatter.SupportedMediaTypes.Add(mediaType);
var formatterContext = new OutputFormatterContext(); var formatterContext = new OutputFormatterContext();
formatterContext.ActionContext = new ActionContext( formatterContext.HttpContext = new DefaultHttpContext();
new DefaultHttpContext(),
new RouteData(),
new ActionDescriptor());
// Act // Act
await formatter.WriteAsync(formatterContext); await formatter.WriteAsync(formatterContext);

View File

@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc
{ {
Object = null, Object = null,
DeclaredType = typeof(string), DeclaredType = typeof(string),
ActionContext = new ActionContext(mockHttpContext.Object, new RouteData(), new ActionDescriptor()), HttpContext = mockHttpContext.Object,
SelectedEncoding = encoding SelectedEncoding = encoding
}; };

View File

@ -143,7 +143,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShimTest
{ {
Object = outputValue, Object = outputValue,
DeclaredType = outputType, DeclaredType = outputType,
ActionContext = new ActionContext(httpContext, routeData: null, actionDescriptor: null) HttpContext = httpContext,
}; };
} }
} }

View File

@ -79,8 +79,9 @@ namespace Microsoft.AspNet.Mvc.Xml
var formatter = new XmlDataContractSerializerInputFormatter(); var formatter = new XmlDataContractSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes("content"); var contentBytes = Encoding.UTF8.GetBytes("content");
var actionContext = GetActionContext(contentBytes, contentType: requestContentType); var modelState = new ModelStateDictionary();
var formatterContext = new InputFormatterContext(actionContext, typeof(string)); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType);
var formatterContext = new InputFormatterContext(httpContext, modelState, typeof(string));
// Act // Act
var result = formatter.CanRead(formatterContext); var result = formatter.CanRead(formatterContext);
@ -285,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.Xml
// Assert // Assert
Assert.NotNull(model); Assert.NotNull(model);
Assert.True(context.ActionContext.HttpContext.Request.Body.CanRead); Assert.True(context.HttpContext.Request.Body.CanRead);
} }
[Fact] [Fact]
@ -328,8 +329,11 @@ namespace Microsoft.AspNet.Mvc.Xml
"<DummyClass><SampleInt>1000</SampleInt></DummyClass>"); "<DummyClass><SampleInt>1000</SampleInt></DummyClass>");
var formatter = new XmlDataContractSerializerInputFormatter(); var formatter = new XmlDataContractSerializerInputFormatter();
var actionContext = GetActionContext(inputBytes, contentType: "application/xml; charset=utf-16");
var context = new InputFormatterContext(actionContext, typeof(TestLevelOne)); var modelState = new ModelStateDictionary();
var httpContext = GetHttpContext(inputBytes, contentType: "application/xml; charset=utf-16");
var context = new InputFormatterContext(httpContext, modelState, typeof(TestLevelOne));
// Act // Act
var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context)); var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context));
@ -381,8 +385,10 @@ namespace Microsoft.AspNet.Mvc.Xml
var formatter = new XmlDataContractSerializerInputFormatter(); var formatter = new XmlDataContractSerializerInputFormatter();
var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input); var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input);
var actionContext = GetActionContext(contentBytes, contentType: "application/xml; charset=utf-16"); var modelState = new ModelStateDictionary();
var context = new InputFormatterContext(actionContext, typeof(TestLevelOne)); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16");
var context = new InputFormatterContext(httpContext, modelState, typeof(TestLevelOne));
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
@ -530,10 +536,10 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(98052, model[0].Zipcode); Assert.Equal(98052, model[0].Zipcode);
Assert.Equal(true, model[0].IsResidential); Assert.Equal(true, model[0].IsResidential);
Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); Assert.Equal(1, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName),
@ -564,10 +570,10 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(98052, model.Zipcode); Assert.Equal(98052, model.Zipcode);
Assert.Equal(true, model.IsResidential); Assert.Equal(true, model.IsResidential);
Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); Assert.Equal(1, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName),
@ -603,10 +609,10 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(98052, model.AddressProperty.Zipcode); Assert.Equal(98052, model.AddressProperty.Zipcode);
Assert.Equal(true, model.AddressProperty.IsResidential); Assert.Equal(true, model.AddressProperty.IsResidential);
Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); Assert.Equal(1, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName),
@ -640,11 +646,11 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(98052, model.Addresses[0].Zipcode); Assert.Equal(98052, model.Addresses[0].Zipcode);
Assert.Equal(true, model.Addresses[0].IsResidential); Assert.Equal(true, model.Addresses[0].IsResidential);
Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); Assert.Equal(1, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
modelStateKey: typeof(Address).FullName, typeof(Address).FullName,
actionContext: context.ActionContext, context,
expectedErrorMessages: new[] new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName),
string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName) string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName)
@ -676,10 +682,10 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(98052, model.Zipcode); Assert.Equal(98052, model.Zipcode);
Assert.Equal(true, model.IsResidential); Assert.Equal(true, model.IsResidential);
Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); Assert.Equal(1, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName),
@ -710,7 +716,7 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.NotNull(model); Assert.NotNull(model);
Assert.Equal(expectedModel.Year, model.Year); Assert.Equal(expectedModel.Year, model.Year);
Assert.Equal(expectedModel.ServicedYears, model.ServicedYears); Assert.Equal(expectedModel.ServicedYears, model.ServicedYears);
Assert.Empty(context.ActionContext.ModelState); Assert.Empty(context.ModelState);
} }
[Fact] [Fact]
@ -745,7 +751,7 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.NotNull(model.CarInfoProperty); Assert.NotNull(model.CarInfoProperty);
Assert.Equal(expectedModel.CarInfoProperty.Year, model.CarInfoProperty.Year); Assert.Equal(expectedModel.CarInfoProperty.Year, model.CarInfoProperty.Year);
Assert.Equal(expectedModel.CarInfoProperty.ServicedYears, model.CarInfoProperty.ServicedYears); Assert.Equal(expectedModel.CarInfoProperty.ServicedYears, model.CarInfoProperty.ServicedYears);
Assert.Empty(context.ActionContext.ModelState); Assert.Empty(context.ModelState);
} }
[Fact] [Fact]
@ -781,10 +787,10 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(expectedModel.Manager.Name, model.Manager.Name); Assert.Equal(expectedModel.Manager.Name, model.Manager.Name);
Assert.Null(model.Manager.Manager); Assert.Null(model.Manager.Manager);
Assert.Equal(1, context.ActionContext.ModelState.Keys.Count); Assert.Equal(1, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Employee).FullName, typeof(Employee).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Employee.Id), typeof(Employee).FullName) string.Format(requiredErrorMessageFormat, nameof(Employee.Id), typeof(Employee).FullName)
@ -810,7 +816,7 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.NotNull(model); Assert.NotNull(model);
Assert.Equal(10, model.Id); Assert.Equal(10, model.Id);
Assert.Equal(true, model.SupportsVirtualization); Assert.Equal(true, model.SupportsVirtualization);
Assert.Empty(context.ActionContext.ModelState); Assert.Empty(context.ModelState);
} }
[Fact] [Fact]
@ -833,7 +839,7 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(1, model.Count); Assert.Equal(1, model.Count);
Assert.Equal(10, model[0].Id); Assert.Equal(10, model[0].Id);
Assert.Equal(true, model[0].SupportsVirtualization); Assert.Equal(true, model[0].SupportsVirtualization);
Assert.Empty(context.ActionContext.ModelState); Assert.Empty(context.ModelState);
} }
[Fact] [Fact]
@ -855,10 +861,10 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.NotNull(model); Assert.NotNull(model);
Assert.Equal(10, model.Id); Assert.Equal(10, model.Id);
Assert.Equal(2, context.ActionContext.ModelState.Keys.Count); Assert.Equal(2, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Product).FullName, typeof(Product).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName) string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName)
@ -866,7 +872,7 @@ namespace Microsoft.AspNet.Mvc.Xml
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName),
@ -895,10 +901,10 @@ namespace Microsoft.AspNet.Mvc.Xml
Assert.Equal(10, model[0].Id); Assert.Equal(10, model[0].Id);
Assert.Equal("Phone", model[0].Name); Assert.Equal("Phone", model[0].Name);
Assert.Equal(2, context.ActionContext.ModelState.Keys.Count); Assert.Equal(2, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Product).FullName, typeof(Product).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName) string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName)
@ -906,7 +912,7 @@ namespace Microsoft.AspNet.Mvc.Xml
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.Zipcode), typeof(Address).FullName),
@ -931,10 +937,10 @@ namespace Microsoft.AspNet.Mvc.Xml
// Assert // Assert
Assert.Null(model); Assert.Null(model);
Assert.Equal(3, context.ActionContext.ModelState.Keys.Count); Assert.Equal(3, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName),
@ -943,7 +949,7 @@ namespace Microsoft.AspNet.Mvc.Xml
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Employee).FullName, typeof(Employee).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Employee.Id), typeof(Employee).FullName) string.Format(requiredErrorMessageFormat, nameof(Employee.Id), typeof(Employee).FullName)
@ -951,7 +957,7 @@ namespace Microsoft.AspNet.Mvc.Xml
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Product).FullName, typeof(Product).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName) string.Format(requiredErrorMessageFormat, nameof(Product.Id), typeof(Product).FullName)
@ -976,17 +982,17 @@ namespace Microsoft.AspNet.Mvc.Xml
// Assert // Assert
Assert.Null(model); Assert.Null(model);
Assert.Equal(3, context.ActionContext.ModelState.Keys.Count); Assert.Equal(3, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(School).FullName, typeof(School).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(School.Id), typeof(School).FullName) string.Format(requiredErrorMessageFormat, nameof(School.Id), typeof(School).FullName)
}); });
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Website).FullName, typeof(Website).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Website.Id), typeof(Website).FullName) string.Format(requiredErrorMessageFormat, nameof(Website.Id), typeof(Website).FullName)
@ -994,7 +1000,7 @@ namespace Microsoft.AspNet.Mvc.Xml
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Student).FullName, typeof(Student).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Student.Id), typeof(Student).FullName) string.Format(requiredErrorMessageFormat, nameof(Student.Id), typeof(Student).FullName)
@ -1019,10 +1025,10 @@ namespace Microsoft.AspNet.Mvc.Xml
// Assert // Assert
Assert.Null(model); Assert.Null(model);
Assert.Equal(2, context.ActionContext.ModelState.Keys.Count); Assert.Equal(2, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Point).FullName, typeof(Point).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Point.X), typeof(Point).FullName), string.Format(requiredErrorMessageFormat, nameof(Point.X), typeof(Point).FullName),
@ -1030,7 +1036,7 @@ namespace Microsoft.AspNet.Mvc.Xml
}); });
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Address).FullName, typeof(Address).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName), string.Format(requiredErrorMessageFormat, nameof(Address.IsResidential), typeof(Address).FullName),
@ -1056,10 +1062,10 @@ namespace Microsoft.AspNet.Mvc.Xml
// Assert // Assert
Assert.Null(model); Assert.Null(model);
Assert.Equal(3, context.ActionContext.ModelState.Keys.Count); Assert.Equal(3, context.ModelState.Keys.Count);
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(Point).FullName, typeof(Point).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format(requiredErrorMessageFormat, nameof(Point.X), typeof(Point).FullName), string.Format(requiredErrorMessageFormat, nameof(Point.X), typeof(Point).FullName),
@ -1067,7 +1073,7 @@ namespace Microsoft.AspNet.Mvc.Xml
}); });
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(GpsCoordinate).FullName, typeof(GpsCoordinate).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format( string.Format(
@ -1081,7 +1087,7 @@ namespace Microsoft.AspNet.Mvc.Xml
}); });
AssertModelStateErrorMessages( AssertModelStateErrorMessages(
typeof(ValueTypePropertiesModel).FullName, typeof(ValueTypePropertiesModel).FullName,
context.ActionContext, context,
expectedErrorMessages: new[] expectedErrorMessages: new[]
{ {
string.Format( string.Format(
@ -1105,11 +1111,11 @@ namespace Microsoft.AspNet.Mvc.Xml
private void AssertModelStateErrorMessages( private void AssertModelStateErrorMessages(
string modelStateKey, string modelStateKey,
ActionContext actionContext, InputFormatterContext context,
IEnumerable<string> expectedErrorMessages) IEnumerable<string> expectedErrorMessages)
{ {
ModelState modelState; ModelState modelState;
actionContext.ModelState.TryGetValue(modelStateKey, out modelState); context.ModelState.TryGetValue(modelStateKey, out modelState);
Assert.NotNull(modelState); Assert.NotNull(modelState);
Assert.NotEmpty(modelState.Errors); Assert.NotEmpty(modelState.Errors);
@ -1140,20 +1146,13 @@ namespace Microsoft.AspNet.Mvc.Xml
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType) private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
{ {
var actionContext = GetActionContext(contentBytes); var httpContext = GetHttpContext(contentBytes);
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType); return new InputFormatterContext(httpContext, new ModelStateDictionary(), modelType);
return new InputFormatterContext(actionContext, metadata.ModelType);
} }
private static ActionContext GetActionContext(byte[] contentBytes, private static HttpContext GetHttpContext(
string contentType = "application/xml") byte[] contentBytes,
{ string contentType = "application/xml")
return new ActionContext(GetHttpContext(contentBytes, contentType),
new AspNet.Routing.RouteData(),
new ActionDescriptor());
}
private static HttpContext GetHttpContext(byte[] contentBytes,
string contentType = "application/xml")
{ {
var request = new Mock<HttpRequest>(); var request = new Mock<HttpRequest>();
var headers = new Mock<IHeaderDictionary>(); var headers = new Mock<IHeaderDictionary>();

View File

@ -102,12 +102,11 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal(expectedOutput,
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8) var content = new StreamReader(body).ReadToEnd();
.ReadToEnd()); XmlAssert.Equal(expectedOutput, content);
Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead);
} }
[Fact] [Fact]
@ -158,17 +157,22 @@ namespace Microsoft.AspNet.Mvc.Xml
// Assert // Assert
Assert.Same(writerSettings, formatter.WriterSettings); Assert.Same(writerSettings, formatter.WriterSettings);
var responseStream = formatterContext.ActionContext.HttpContext.Response.Body;
Assert.NotNull(responseStream); var body = formatterContext.HttpContext.Response.Body;
responseStream.Position = 0; body.Position = 0;
var actualOutput = new StreamReader(responseStream, Encoding.UTF8).ReadToEnd();
XmlAssert.Equal(expectedOutput, actualOutput); var content = new StreamReader(body).ReadToEnd();
XmlAssert.Equal(expectedOutput, content);
} }
[Fact] [Fact]
public async Task WriteAsync_WritesSimpleTypes() public async Task WriteAsync_WritesSimpleTypes()
{ {
// Arrange // Arrange
var expectedOutput =
"<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<SampleInt>10</SampleInt></DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var formatter = new XmlDataContractSerializerOutputFormatter(); var formatter = new XmlDataContractSerializerOutputFormatter();
var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
@ -177,18 +181,23 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<SampleInt>10</SampleInt></DummyClass>", var content = new StreamReader(body).ReadToEnd();
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8) XmlAssert.Equal(expectedOutput, content);
.ReadToEnd());
} }
[Fact] [Fact]
public async Task WriteAsync_WritesComplexTypes() public async Task WriteAsync_WritesComplexTypes()
{ {
// Arrange // Arrange
var expectedOutput =
"<TestLevelTwo xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<SampleString>TestString</SampleString>" +
"<TestOne><SampleInt>10</SampleInt><sampleString>TestLevelOne string</sampleString>" +
"</TestOne></TestLevelTwo>";
var sampleInput = new TestLevelTwo var sampleInput = new TestLevelTwo
{ {
SampleString = "TestString", SampleString = "TestString",
@ -205,24 +214,26 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<TestLevelTwo xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<SampleString>TestString</SampleString>" + var content = new StreamReader(body).ReadToEnd();
"<TestOne><SampleInt>10</SampleInt><sampleString>TestLevelOne string</sampleString>" + XmlAssert.Equal(expectedOutput, content);
"</TestOne></TestLevelTwo>",
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
.ReadToEnd());
} }
[Fact] [Fact]
public async Task WriteAsync_WritesOnModifiedWriterSettings() public async Task WriteAsync_WritesOnModifiedWriterSettings()
{ {
// Arrange // Arrange
var expectedOutput =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<SampleInt>10</SampleInt></DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
var formatter = new XmlDataContractSerializerOutputFormatter( var formatter = new XmlDataContractSerializerOutputFormatter(
new System.Xml.XmlWriterSettings new XmlWriterSettings
{ {
OmitXmlDeclaration = false, OmitXmlDeclaration = false,
CloseOutput = false CloseOutput = false
@ -232,19 +243,22 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + var content = new StreamReader(body).ReadToEnd();
"<SampleInt>10</SampleInt></DummyClass>", XmlAssert.Equal(expectedOutput, content);
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
Encoding.UTF8).ReadToEnd());
} }
[Fact] [Fact]
public async Task WriteAsync_WritesUTF16Output() public async Task WriteAsync_WritesUTF16Output()
{ {
// Arrange // Arrange
var expectedOutput =
"<?xml version=\"1.0\" encoding=\"utf-16\"?>" +
"<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<SampleInt>10</SampleInt></DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType(), var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType(),
"application/xml; charset=utf-16"); "application/xml; charset=utf-16");
@ -255,19 +269,21 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<?xml version=\"1.0\" encoding=\"utf-16\"?>" +
"<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + var content = new StreamReader(body).ReadToEnd();
"<SampleInt>10</SampleInt></DummyClass>", XmlAssert.Equal(expectedOutput, content);
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
Encodings.UTF16EncodingLittleEndian).ReadToEnd());
} }
[Fact] [Fact]
public async Task WriteAsync_WritesIndentedOutput() public async Task WriteAsync_WritesIndentedOutput()
{ {
// Arrange // Arrange
var expectedOutput =
"<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"\r\n <SampleInt>10</SampleInt>\r\n</DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var formatter = new XmlDataContractSerializerOutputFormatter(); var formatter = new XmlDataContractSerializerOutputFormatter();
formatter.WriterSettings.Indent = true; formatter.WriterSettings.Indent = true;
@ -277,13 +293,11 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
var outputString = new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
Encoding.UTF8).ReadToEnd(); var content = new StreamReader(body).ReadToEnd();
XmlAssert.Equal("<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" + XmlAssert.Equal(expectedOutput, content);
"\r\n <SampleInt>10</SampleInt>\r\n</DummyClass>",
outputString);
} }
[Fact] [Fact]
@ -298,8 +312,8 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead); Assert.True(body.CanRead);
} }
[Fact] [Fact]
@ -310,7 +324,7 @@ namespace Microsoft.AspNet.Mvc.Xml
var formatter = new XmlDataContractSerializerOutputFormatter(); var formatter = new XmlDataContractSerializerOutputFormatter();
var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
var response = outputFormatterContext.ActionContext.HttpContext.Response; var response = outputFormatterContext.HttpContext.Response;
response.Body = FlushReportingStream.GetThrowingStream(); response.Body = FlushReportingStream.GetThrowingStream();
// Act & Assert // Act & Assert
@ -447,11 +461,11 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
var actualOutput = new StreamReader(
outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8).ReadToEnd(); var content = new StreamReader(body).ReadToEnd();
XmlAssert.Equal(expectedOutput, actualOutput); XmlAssert.Equal(expectedOutput, content);
} }
[Fact] [Fact]
@ -491,11 +505,11 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
var actualOutput = new StreamReader(
outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8).ReadToEnd(); var content = new StreamReader(body).ReadToEnd();
XmlAssert.Equal(expectedOutput, actualOutput); XmlAssert.Equal(expectedOutput, content);
} }
[Fact] [Fact]
@ -535,11 +549,11 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
var actualOutput = new StreamReader(
outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8).ReadToEnd(); var content = new StreamReader(body).ReadToEnd();
XmlAssert.Equal(expectedOutput, actualOutput); XmlAssert.Equal(expectedOutput, content);
} }
private OutputFormatterContext GetOutputFormatterContext(object outputValue, Type outputType, private OutputFormatterContext GetOutputFormatterContext(object outputValue, Type outputType,
@ -549,23 +563,26 @@ namespace Microsoft.AspNet.Mvc.Xml
{ {
Object = outputValue, Object = outputValue,
DeclaredType = outputType, DeclaredType = outputType,
ActionContext = GetActionContext(contentType) HttpContext = GetHttpContext(contentType)
}; };
} }
private static ActionContext GetActionContext(string contentType) private static HttpContext GetHttpContext(string contentType)
{ {
var request = new Mock<HttpRequest>(); var request = new Mock<HttpRequest>();
var headers = new HeaderDictionary(new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)); var headers = new HeaderDictionary(new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase));
headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset; headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset;
request.Setup(r => r.ContentType).Returns(contentType); request.Setup(r => r.ContentType).Returns(contentType);
request.SetupGet(r => r.Headers).Returns(headers); request.SetupGet(r => r.Headers).Returns(headers);
var response = new Mock<HttpResponse>(); var response = new Mock<HttpResponse>();
response.SetupGet(f => f.Body).Returns(new MemoryStream()); response.SetupGet(f => f.Body).Returns(new MemoryStream());
var httpContext = new Mock<HttpContext>(); var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(c => c.Request).Returns(request.Object); httpContext.SetupGet(c => c.Request).Returns(request.Object);
httpContext.SetupGet(c => c.Response).Returns(response.Object); httpContext.SetupGet(c => c.Response).Returns(response.Object);
return new ActionContext(httpContext.Object, routeData: null, actionDescriptor: null); return httpContext.Object;
} }
private class TestXmlDataContractSerializerOutputFormatter : XmlDataContractSerializerOutputFormatter private class TestXmlDataContractSerializerOutputFormatter : XmlDataContractSerializerOutputFormatter

View File

@ -56,8 +56,10 @@ namespace Microsoft.AspNet.Mvc.Xml
var formatter = new XmlSerializerInputFormatter(); var formatter = new XmlSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes("content"); var contentBytes = Encoding.UTF8.GetBytes("content");
var actionContext = GetActionContext(contentBytes, contentType: requestContentType); var modelState = new ModelStateDictionary();
var formatterContext = new InputFormatterContext(actionContext, typeof(string)); var httpContext = GetHttpContext(contentBytes, contentType: requestContentType);
var formatterContext = new InputFormatterContext(httpContext, modelState, typeof(string));
// Act // Act
var result = formatter.CanRead(formatterContext); var result = formatter.CanRead(formatterContext);
@ -292,7 +294,7 @@ namespace Microsoft.AspNet.Mvc.Xml
// Assert // Assert
Assert.NotNull(model); Assert.NotNull(model);
Assert.True(context.ActionContext.HttpContext.Request.Body.CanRead); Assert.True(context.HttpContext.Request.Body.CanRead);
} }
[Fact] [Fact]
@ -337,8 +339,11 @@ namespace Microsoft.AspNet.Mvc.Xml
"<DummyClass><SampleInt>1000</SampleInt></DummyClass>"); "<DummyClass><SampleInt>1000</SampleInt></DummyClass>");
var formatter = new XmlSerializerInputFormatter(); var formatter = new XmlSerializerInputFormatter();
var actionContext = GetActionContext(inputBytes, contentType: "application/xml; charset=utf-16");
var context = new InputFormatterContext(actionContext, typeof(TestLevelOne)); var modelState = new ModelStateDictionary();
var httpContext = GetHttpContext(inputBytes, contentType: "application/xml; charset=utf-16");
var context = new InputFormatterContext(httpContext, modelState, typeof(TestLevelOne));
// Act and Assert // Act and Assert
var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context)); var ex = await Assert.ThrowsAsync(expectedException, () => formatter.ReadAsync(context));
@ -392,8 +397,9 @@ namespace Microsoft.AspNet.Mvc.Xml
var formatter = new XmlSerializerInputFormatter(); var formatter = new XmlSerializerInputFormatter();
var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input); var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input);
var actionContext = GetActionContext(contentBytes, contentType: "application/xml; charset=utf-16"); var modelState = new ModelStateDictionary();
var context = new InputFormatterContext(actionContext, typeof(TestLevelOne)); var httpContext = GetHttpContext(contentBytes, contentType: "application/xml; charset=utf-16");
var context = new InputFormatterContext(httpContext, modelState, typeof(TestLevelOne));
// Act // Act
var model = await formatter.ReadAsync(context); var model = await formatter.ReadAsync(context);
@ -410,21 +416,13 @@ namespace Microsoft.AspNet.Mvc.Xml
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType) private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
{ {
var actionContext = GetActionContext(contentBytes); var httpContext = GetHttpContext(contentBytes);
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(modelType); return new InputFormatterContext(httpContext, new ModelStateDictionary(), modelType);
return new InputFormatterContext(actionContext, metadata.ModelType);
} }
private static ActionContext GetActionContext(byte[] contentBytes, private static HttpContext GetHttpContext(
string contentType = "application/xml") byte[] contentBytes,
{ string contentType = "application/xml")
return new ActionContext(GetHttpContext(contentBytes, contentType),
new AspNet.Routing.RouteData(),
new ActionDescriptor());
}
private static HttpContext GetHttpContext(byte[] contentBytes,
string contentType = "application/xml")
{ {
var request = new Mock<HttpRequest>(); var request = new Mock<HttpRequest>();
var headers = new Mock<IHeaderDictionary>(); var headers = new Mock<IHeaderDictionary>();

View File

@ -60,12 +60,11 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal(expectedOutput,
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8) var content = new StreamReader(body).ReadToEnd();
.ReadToEnd()); XmlAssert.Equal(expectedOutput, content);
Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead);
} }
[Fact] [Fact]
@ -115,18 +114,21 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(formatterContext); await formatter.WriteAsync(formatterContext);
// Assert // Assert
Assert.Same(writerSettings, formatter.WriterSettings); var body = formatterContext.HttpContext.Response.Body;
var responseStream = formatterContext.ActionContext.HttpContext.Response.Body; body.Position = 0;
Assert.NotNull(responseStream);
responseStream.Position = 0; var content = new StreamReader(body).ReadToEnd();
var actualOutput = new StreamReader(responseStream, Encoding.UTF8).ReadToEnd(); XmlAssert.Equal(expectedOutput, content);
XmlAssert.Equal(expectedOutput, actualOutput);
} }
[Fact] [Fact]
public async Task XmlSerializerOutputFormatterWritesSimpleTypes() public async Task XmlSerializerOutputFormatterWritesSimpleTypes()
{ {
// Arrange // Arrange
var expectedOutput =
"<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleInt>10</SampleInt></DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var formatter = new XmlSerializerOutputFormatter(); var formatter = new XmlSerializerOutputFormatter();
var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
@ -135,19 +137,23 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleInt>10</SampleInt></DummyClass>", var content = new StreamReader(body).ReadToEnd();
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8) XmlAssert.Equal(expectedOutput, content);
.ReadToEnd());
Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead);
} }
[Fact] [Fact]
public async Task XmlSerializerOutputFormatterWritesComplexTypes() public async Task XmlSerializerOutputFormatterWritesComplexTypes()
{ {
// Arrange // Arrange
var expectedOutput =
"<TestLevelTwo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleString>TestString</SampleString>" +
"<TestOne><sampleString>TestLevelOne string</sampleString>" +
"<SampleInt>10</SampleInt></TestOne></TestLevelTwo>";
var sampleInput = new TestLevelTwo var sampleInput = new TestLevelTwo
{ {
SampleString = "TestString", SampleString = "TestString",
@ -164,20 +170,22 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<TestLevelTwo xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleString>TestString</SampleString>" + var content = new StreamReader(body).ReadToEnd();
"<TestOne><sampleString>TestLevelOne string</sampleString>" + XmlAssert.Equal(expectedOutput, content);
"<SampleInt>10</SampleInt></TestOne></TestLevelTwo>",
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
.ReadToEnd());
} }
[Fact] [Fact]
public async Task XmlSerializerOutputFormatterWritesOnModifiedWriterSettings() public async Task XmlSerializerOutputFormatterWritesOnModifiedWriterSettings()
{ {
// Arrange // Arrange
var expectedOutput =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleInt>10</SampleInt></DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
var formatter = new XmlSerializerOutputFormatter( var formatter = new XmlSerializerOutputFormatter(
@ -191,19 +199,22 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + var content = new StreamReader(body).ReadToEnd();
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleInt>10</SampleInt></DummyClass>", XmlAssert.Equal(expectedOutput, content);
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
.ReadToEnd());
} }
[Fact] [Fact]
public async Task XmlSerializerOutputFormatterWritesUTF16Output() public async Task XmlSerializerOutputFormatterWritesUTF16Output()
{ {
// Arrange // Arrange
var expectedOutput =
"<?xml version=\"1.0\" encoding=\"utf-16\"?>" +
"<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleInt>10</SampleInt></DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var outputFormatterContext = var outputFormatterContext =
GetOutputFormatterContext(sampleInput, sampleInput.GetType(), "application/xml; charset=utf-16"); GetOutputFormatterContext(sampleInput, sampleInput.GetType(), "application/xml; charset=utf-16");
@ -214,19 +225,21 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
XmlAssert.Equal("<?xml version=\"1.0\" encoding=\"utf-16\"?>" +
"<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + var content = new StreamReader(body).ReadToEnd();
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleInt>10</SampleInt></DummyClass>", XmlAssert.Equal(expectedOutput, content);
new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
Encodings.UTF16EncodingLittleEndian).ReadToEnd());
} }
[Fact] [Fact]
public async Task XmlSerializerOutputFormatterWritesIndentedOutput() public async Task XmlSerializerOutputFormatterWritesIndentedOutput()
{ {
// Arrange // Arrange
var expectedOutput =
"<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <SampleInt>10</SampleInt>\r\n</DummyClass>";
var sampleInput = new DummyClass { SampleInt = 10 }; var sampleInput = new DummyClass { SampleInt = 10 };
var formatter = new XmlSerializerOutputFormatter(); var formatter = new XmlSerializerOutputFormatter();
formatter.WriterSettings.Indent = true; formatter.WriterSettings.Indent = true;
@ -236,13 +249,11 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); var body = outputFormatterContext.HttpContext.Response.Body;
outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0; body.Position = 0;
var outputString = new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
Encoding.UTF8).ReadToEnd(); var content = new StreamReader(body).ReadToEnd();
XmlAssert.Equal("<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + XmlAssert.Equal(expectedOutput, content);
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <SampleInt>10</SampleInt>\r\n</DummyClass>",
outputString);
} }
[Fact] [Fact]
@ -257,8 +268,8 @@ namespace Microsoft.AspNet.Mvc.Xml
await formatter.WriteAsync(outputFormatterContext); await formatter.WriteAsync(outputFormatterContext);
// Assert // Assert
Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body); Assert.NotNull(outputFormatterContext.HttpContext.Response.Body);
Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead); Assert.True(outputFormatterContext.HttpContext.Response.Body.CanRead);
} }
public static IEnumerable<object[]> TypesForCanWriteResult public static IEnumerable<object[]> TypesForCanWriteResult
@ -304,7 +315,7 @@ namespace Microsoft.AspNet.Mvc.Xml
var formatter = new XmlSerializerOutputFormatter(); var formatter = new XmlSerializerOutputFormatter();
var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
var response = outputFormatterContext.ActionContext.HttpContext.Response; var response = outputFormatterContext.HttpContext.Response;
response.Body = FlushReportingStream.GetThrowingStream(); response.Body = FlushReportingStream.GetThrowingStream();
// Act & Assert // Act & Assert
@ -346,30 +357,35 @@ namespace Microsoft.AspNet.Mvc.Xml
} }
} }
private OutputFormatterContext GetOutputFormatterContext(object outputValue, Type outputType, private OutputFormatterContext GetOutputFormatterContext(
string contentType = "application/xml; charset=utf-8") object outputValue,
Type outputType,
string contentType = "application/xml; charset=utf-8")
{ {
return new OutputFormatterContext return new OutputFormatterContext
{ {
Object = outputValue, Object = outputValue,
DeclaredType = outputType, DeclaredType = outputType,
ActionContext = GetActionContext(contentType) HttpContext = GetHttpContext(contentType)
}; };
} }
private static ActionContext GetActionContext(string contentType) private static HttpContext GetHttpContext(string contentType)
{ {
var request = new Mock<HttpRequest>(); var request = new Mock<HttpRequest>();
var headers = new HeaderDictionary(new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)); var headers = new HeaderDictionary(new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase));
headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset; headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset;
request.Setup(r => r.ContentType).Returns(contentType); request.Setup(r => r.ContentType).Returns(contentType);
request.SetupGet(r => r.Headers).Returns(headers); request.SetupGet(r => r.Headers).Returns(headers);
var response = new Mock<HttpResponse>(); var response = new Mock<HttpResponse>();
response.SetupGet(f => f.Body).Returns(new MemoryStream()); response.SetupGet(f => f.Body).Returns(new MemoryStream());
var httpContext = new Mock<HttpContext>(); var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(c => c.Request).Returns(request.Object); httpContext.SetupGet(c => c.Request).Returns(request.Object);
httpContext.SetupGet(c => c.Response).Returns(response.Object); httpContext.SetupGet(c => c.Response).Returns(response.Object);
return new ActionContext(httpContext.Object, routeData: null, actionDescriptor: null); return httpContext.Object;
} }
private class TestXmlSerializerOutputFormatter : XmlSerializerOutputFormatter private class TestXmlSerializerOutputFormatter : XmlSerializerOutputFormatter

View File

@ -35,7 +35,7 @@ namespace ContentNegotiationWebSite
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) public override async Task WriteResponseBodyAsync(OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
response.ContentType = ContentType + ";charset=utf-8"; response.ContentType = ContentType + ";charset=utf-8";
await response.WriteAsync(context.Object.ToString()); await response.WriteAsync(context.Object.ToString());
} }

View File

@ -33,7 +33,7 @@ namespace ContentNegotiationWebSite
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) public override async Task WriteResponseBodyAsync(OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
response.ContentType = "text/plain;charset=utf-8"; response.ContentType = "text/plain;charset=utf-8";
await response.WriteAsync(context.Object as string); await response.WriteAsync(context.Object as string);
} }

View File

@ -39,7 +39,7 @@ namespace ContentNegotiationWebSite
builder.AppendLine(); builder.AppendLine();
builder.AppendLine("END:VCARD"); builder.AppendLine("END:VCARD");
var responseStream = new NonDisposableStream(context.ActionContext.HttpContext.Response.Body); var responseStream = new NonDisposableStream(context.HttpContext.Response.Body);
using (var writer = new StreamWriter(responseStream, context.SelectedEncoding, bufferSize: 1024)) using (var writer = new StreamWriter(responseStream, context.SelectedEncoding, bufferSize: 1024))
{ {
await writer.WriteAsync(builder.ToString()); await writer.WriteAsync(builder.ToString());

View File

@ -42,7 +42,7 @@ namespace ContentNegotiationWebSite
builder.AppendLine(); builder.AppendLine();
builder.AppendLine("END:VCARD"); builder.AppendLine("END:VCARD");
var responseStream = new NonDisposableStream(context.ActionContext.HttpContext.Response.Body); var responseStream = new NonDisposableStream(context.HttpContext.Response.Body);
using (var writer = new StreamWriter(responseStream, context.SelectedEncoding, bufferSize: 1024)) using (var writer = new StreamWriter(responseStream, context.SelectedEncoding, bufferSize: 1024))
{ {
await writer.WriteAsync(builder.ToString()); await writer.WriteAsync(builder.ToString());

View File

@ -27,7 +27,7 @@ namespace FormatFilterWebSite
var actionReturn = context.Object as Product; var actionReturn = context.Object as Product;
if (actionReturn != null) if (actionReturn != null)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
context.SelectedContentType = contentType; context.SelectedContentType = contentType;
return true; return true;
} }
@ -37,7 +37,7 @@ namespace FormatFilterWebSite
public override async Task WriteResponseBodyAsync(OutputFormatterContext context) public override async Task WriteResponseBodyAsync(OutputFormatterContext context)
{ {
var response = context.ActionContext.HttpContext.Response; var response = context.HttpContext.Response;
await response.WriteAsync(context.Object.ToString()); await response.WriteAsync(context.Object.ToString());
} }
} }

View File

@ -19,7 +19,7 @@ namespace FormatterWebSite
public override Task<object> ReadRequestBodyAsync(InputFormatterContext context) public override Task<object> ReadRequestBodyAsync(InputFormatterContext context)
{ {
var request = context.ActionContext.HttpContext.Request; var request = context.HttpContext.Request;
MediaTypeHeaderValue requestContentType = null; MediaTypeHeaderValue requestContentType = null;
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType); MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);
var effectiveEncoding = SelectCharacterEncoding(requestContentType); var effectiveEncoding = SelectCharacterEncoding(requestContentType);