1. Moving input formatting related classes to MVC Core.(for tests as well).
2. Cleaning up the IInputFormatter to the final version. 3. Updating the input formatters and the context to be compliant with the IInputFormatter interface. 4. Adding Functional Tests. - Not cleaning up TempInputFormatterProvider. Conflicts: src/Microsoft.AspNet.Mvc.Core/Formatters/InputFormatter.cs src/Microsoft.AspNet.Mvc.Core/Formatters/JsonInputFormatter.cs src/Microsoft.AspNet.Mvc.Core/Formatters/TempInputFormatterProvider.cs src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerInputFormatter.cs src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerInputFormatter.cs src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj src/Microsoft.AspNet.Mvc.Core/ReflectedActionInvoker.cs src/Microsoft.AspNet.Mvc.ModelBinding/Microsoft.AspNet.Mvc.ModelBinding.kproj test/Microsoft.AspNet.Mvc.Core.Test/Microsoft.AspNet.Mvc.Core.Test.kproj Conflicts: src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Microsoft.AspNet.Mvc.HeaderValueAbstractions.kproj src/Microsoft.AspNet.Mvc.ModelBinding/Microsoft.AspNet.Mvc.ModelBinding.kproj src/Microsoft.AspNet.Mvc.ModelBinding/ValueProviders/FormValueProviderFactory.cs test/Microsoft.AspNet.Mvc.Core.Test/Microsoft.AspNet.Mvc.Core.Test.kproj test/Microsoft.AspNet.Mvc.ModelBinding.Test/Microsoft.AspNet.Mvc.ModelBinding.Test.kproj Conflicts: src/Microsoft.AspNet.Mvc.Core/Formatters/FormattingUtilities.cs src/Microsoft.AspNet.Mvc.Core/Formatters/TempInputFormatterProvider.cs
This commit is contained in:
parent
4f69e17f53
commit
64d797a489
|
|
@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var incomingAcceptHeader = HeaderParsingHelpers.GetAcceptHeaders(
|
var incomingAcceptHeader = HeaderParsingHelpers.GetAcceptHeaders(
|
||||||
formatterContext.ActionContext.HttpContext.Request.Accept);
|
formatterContext.ActionContext.HttpContext.Request.Accept);
|
||||||
var sortedAcceptHeaders = SortMediaTypeWithQualityHeaderValues(incomingAcceptHeader)
|
var sortedAcceptHeaders = SortMediaTypeWithQualityHeaderValues(incomingAcceptHeader)
|
||||||
.Where(header => header.Quality != FormattingUtilities.NoMatch)
|
.Where(header => header.Quality != HttpHeaderUtilitites.NoMatch)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
IOutputFormatter selectedFormatter = null;
|
IOutputFormatter selectedFormatter = null;
|
||||||
|
|
|
||||||
|
|
@ -241,18 +241,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
modelAccessor: null,
|
modelAccessor: null,
|
||||||
modelType: parameterType);
|
modelType: parameterType);
|
||||||
var providerContext = new InputFormatterProviderContext(
|
var providerContext = new InputFormatterProviderContext(
|
||||||
actionBindingContext.ActionContext.HttpContext,
|
actionBindingContext.ActionContext,
|
||||||
modelMetadata,
|
modelMetadata,
|
||||||
modelState);
|
modelState);
|
||||||
|
|
||||||
var inputFormatter = actionBindingContext.InputFormatterProvider.GetInputFormatter(
|
var inputFormatter = actionBindingContext.InputFormatterProvider.GetInputFormatter(
|
||||||
providerContext);
|
providerContext);
|
||||||
|
|
||||||
var formatterContext = new InputFormatterContext(actionBindingContext.ActionContext.HttpContext,
|
var formatterContext = new InputFormatterContext(actionBindingContext.ActionContext,
|
||||||
modelMetadata,
|
modelMetadata.ModelType);
|
||||||
modelState);
|
parameterValues[parameter.Name] = await inputFormatter.ReadAsync(formatterContext);
|
||||||
await inputFormatter.ReadAsync(formatterContext);
|
|
||||||
parameterValues[parameter.Name] = formatterContext.Model;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stream that delegates to an inner stream.
|
/// Stream that delegates to an inner stream.
|
||||||
|
|
@ -5,9 +5,10 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains methods which are used by input formatters.
|
/// Contains methods which are used by input formatters.
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an object from the request body.
|
||||||
|
/// </summary>
|
||||||
|
public interface IInputFormatter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this <see cref="IInputFormatter"/> can de-serialize
|
||||||
|
/// an object of the specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Input formatter context associated with this call.</param>
|
||||||
|
/// <returns>True if this <see cref="IInputFormatter"/> supports the passed in
|
||||||
|
/// request's content-type and is able to de-serialize the request body.
|
||||||
|
/// False otherwise.</returns>
|
||||||
|
bool CanRead(InputFormatterContext context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called during deserialization to read an object from the request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Input formatter context associated with this call.</param>
|
||||||
|
/// <returns>A task that deserializes the request body.</returns>
|
||||||
|
Task<object> ReadAsync(InputFormatterContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public interface IInputFormatterProvider
|
public interface IInputFormatterProvider
|
||||||
{
|
{
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents information used by an input formatter for
|
||||||
|
/// deserializing the request body into an object.
|
||||||
|
/// </summary>
|
||||||
|
public class InputFormatterContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="InputFormatterContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
public InputFormatterContext([NotNull] ActionContext actionContext,
|
||||||
|
[NotNull] Type modelType)
|
||||||
|
{
|
||||||
|
ActionContext = actionContext;
|
||||||
|
ModelType = modelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Action context associated with the current call.
|
||||||
|
/// </summary>
|
||||||
|
public ActionContext ActionContext { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the expected type of the model represented by the request body.
|
||||||
|
/// </summary>
|
||||||
|
public Type ModelType { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,21 +2,22 @@
|
||||||
// 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 Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class InputFormatterProviderContext
|
public class InputFormatterProviderContext
|
||||||
{
|
{
|
||||||
public InputFormatterProviderContext([NotNull] HttpContext httpContext,
|
public InputFormatterProviderContext([NotNull] ActionContext actionContext,
|
||||||
[NotNull] ModelMetadata metadata,
|
[NotNull] ModelMetadata metadata,
|
||||||
[NotNull] ModelStateDictionary modelState)
|
[NotNull] ModelStateDictionary modelState)
|
||||||
{
|
{
|
||||||
HttpContext = httpContext;
|
ActionContext = actionContext;
|
||||||
Metadata = metadata;
|
Metadata = metadata;
|
||||||
ModelState = modelState;
|
ModelState = modelState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpContext HttpContext { get; private set; }
|
public ActionContext ActionContext { get; private set; }
|
||||||
|
|
||||||
public ModelMetadata Metadata { get; private set; }
|
public ModelMetadata Metadata { get; private set; }
|
||||||
|
|
||||||
|
|
@ -8,10 +8,11 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class JsonInputFormatter : IInputFormatter
|
public class JsonInputFormatter : IInputFormatter
|
||||||
{
|
{
|
||||||
|
|
@ -66,20 +67,34 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets if deserialization errors are captured. When set, these errors appear in
|
/// Gets or sets if deserialization errors are captured. When set, these errors appear in
|
||||||
/// the <see cref="ModelStateDictionary"/> instance of <see cref="InputFormatterContext"/>.
|
/// the <see cref="ActionContext.ModelState"/> instance of <see cref="InputFormatterContext"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CaptureDeserilizationErrors { get; set; }
|
public bool CaptureDeserilizationErrors { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task ReadAsync([NotNull] InputFormatterContext context)
|
public bool CanRead(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var request = context.HttpContext.Request;
|
var contentType = context.ActionContext.HttpContext.Request.ContentType;
|
||||||
|
MediaTypeHeaderValue requestContentType;
|
||||||
|
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SupportedMediaTypes
|
||||||
|
.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<object> ReadAsync([NotNull] InputFormatterContext context)
|
||||||
|
{
|
||||||
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
if (request.ContentLength == 0)
|
if (request.ContentLength == 0)
|
||||||
{
|
{
|
||||||
var modelType = context.Metadata.ModelType;
|
var modelType = context.ModelType;
|
||||||
context.Model = modelType.GetTypeInfo().IsValueType ? Activator.CreateInstance(modelType) :
|
var model = modelType.GetTypeInfo().IsValueType ? Activator.CreateInstance(modelType) :
|
||||||
null;
|
null;
|
||||||
return;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaTypeHeaderValue requestContentType = null;
|
MediaTypeHeaderValue requestContentType = null;
|
||||||
|
|
@ -89,7 +104,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// Never non-null since SelectCharacterEncoding() throws in error / not found scenarios
|
// Never non-null since SelectCharacterEncoding() throws in error / not found scenarios
|
||||||
var effectiveEncoding = SelectCharacterEncoding(requestContentType);
|
var effectiveEncoding = SelectCharacterEncoding(requestContentType);
|
||||||
|
|
||||||
context.Model = await ReadInternal(context, effectiveEncoding);
|
return await ReadInternal(context, effectiveEncoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -118,8 +133,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private Task<object> ReadInternal(InputFormatterContext context,
|
private Task<object> ReadInternal(InputFormatterContext context,
|
||||||
Encoding effectiveEncoding)
|
Encoding effectiveEncoding)
|
||||||
{
|
{
|
||||||
var type = context.Metadata.ModelType;
|
var type = context.ModelType;
|
||||||
var request = context.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
|
|
||||||
using (var jsonReader = CreateJsonReader(context, request.Body, effectiveEncoding))
|
using (var jsonReader = CreateJsonReader(context, request.Body, effectiveEncoding))
|
||||||
{
|
{
|
||||||
|
|
@ -133,7 +148,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
errorHandler = (sender, e) =>
|
errorHandler = (sender, e) =>
|
||||||
{
|
{
|
||||||
var exception = e.ErrorContext.Error;
|
var exception = e.ErrorContext.Error;
|
||||||
context.ModelState.AddModelError(e.ErrorContext.Path, e.ErrorContext.Error);
|
context.ActionContext.ModelState.AddModelError(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
|
||||||
// overflow the stack for x64 CLR processes
|
// overflow the stack for x64 CLR processes
|
||||||
|
|
@ -181,7 +196,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
// No supported encoding was found so there is no way for us to start reading.
|
// No supported encoding was found so there is no way for us to start reading.
|
||||||
throw new InvalidOperationException(Resources.FormatMediaTypeFormatterNoEncoding(GetType().FullName));
|
throw new InvalidOperationException(Resources.FormatInputFormatterNoEncoding(GetType().FullName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,8 +85,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
private static int CompareBasedOnQualityFactor(MediaTypeWithQualityHeaderValue mediaType1,
|
private static int CompareBasedOnQualityFactor(MediaTypeWithQualityHeaderValue mediaType1,
|
||||||
MediaTypeWithQualityHeaderValue mediaType2)
|
MediaTypeWithQualityHeaderValue mediaType2)
|
||||||
{
|
{
|
||||||
var mediaType1Quality = mediaType1.Quality ?? FormattingUtilities.Match;
|
var mediaType1Quality = mediaType1.Quality ?? HttpHeaderUtilitites.Match;
|
||||||
var mediaType2Quality = mediaType2.Quality ?? FormattingUtilities.Match;
|
var mediaType2Quality = mediaType2.Quality ?? HttpHeaderUtilitites.Match;
|
||||||
var qualityDifference = mediaType1Quality - mediaType2Quality;
|
var qualityDifference = mediaType1Quality - mediaType2Quality;
|
||||||
if (qualityDifference < 0)
|
if (qualityDifference < 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
var sortedAcceptCharsetHeaders = acceptCharsetHeaders
|
var sortedAcceptCharsetHeaders = acceptCharsetHeaders
|
||||||
.Where(acceptCharset =>
|
.Where(acceptCharset =>
|
||||||
acceptCharset.Quality != FormattingUtilities.NoMatch)
|
acceptCharset.Quality != HttpHeaderUtilitites.NoMatch)
|
||||||
.OrderByDescending(
|
.OrderByDescending(
|
||||||
m => m, StringWithQualityHeaderValueComparer.QualityComparer);
|
m => m, StringWithQualityHeaderValueComparer.QualityComparer);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public int Compare([NotNull] StringWithQualityHeaderValue stringWithQuality1,
|
public int Compare([NotNull] StringWithQualityHeaderValue stringWithQuality1,
|
||||||
[NotNull] StringWithQualityHeaderValue stringWithQuality2)
|
[NotNull] StringWithQualityHeaderValue stringWithQuality2)
|
||||||
{
|
{
|
||||||
var quality1 = stringWithQuality1.Quality ?? FormattingUtilities.Match;
|
var quality1 = stringWithQuality1.Quality ?? HttpHeaderUtilitites.Match;
|
||||||
var quality2 = stringWithQuality2.Quality ?? FormattingUtilities.Match;
|
var quality2 = stringWithQuality2.Quality ?? HttpHeaderUtilitites.Match;
|
||||||
var qualityDifference = quality1 - quality2;
|
var qualityDifference = quality1 - quality2;
|
||||||
if (qualityDifference < 0)
|
if (qualityDifference < 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,7 @@
|
||||||
// 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 System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
|
||||||
using Microsoft.Framework.DependencyInjection;
|
|
||||||
using Microsoft.Framework.OptionsModel;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -23,20 +17,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public IInputFormatter GetInputFormatter(InputFormatterProviderContext context)
|
public IInputFormatter GetInputFormatter(InputFormatterProviderContext context)
|
||||||
{
|
{
|
||||||
var request = context.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
MediaTypeHeaderValue contentType;
|
var formatterContext = new InputFormatterContext(context.ActionContext,
|
||||||
if (!MediaTypeHeaderValue.TryParse(request.ContentType, out contentType))
|
context.Metadata.ModelType);
|
||||||
{
|
|
||||||
// TODO: https://github.com/aspnet/Mvc/issues/458
|
|
||||||
throw new InvalidOperationException("400: Bad Request");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// TODO: https://github.com/aspnet/Mvc/issues/1014
|
||||||
var formatters = _defaultFormattersProvider.InputFormatters;
|
var formatters = _defaultFormattersProvider.InputFormatters;
|
||||||
foreach (var formatter in formatters)
|
foreach (var formatter in formatters)
|
||||||
{
|
{
|
||||||
var formatterMatched = formatter.SupportedMediaTypes
|
var formatterMatched = formatter.CanRead(formatterContext);
|
||||||
.Any(supportedMediaType =>
|
|
||||||
supportedMediaType.IsSubsetOf(contentType));
|
|
||||||
if (formatterMatched)
|
if (formatterMatched)
|
||||||
{
|
{
|
||||||
return formatter;
|
return formatter;
|
||||||
|
|
@ -46,7 +35,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// TODO: https://github.com/aspnet/Mvc/issues/458
|
// TODO: https://github.com/aspnet/Mvc/issues/458
|
||||||
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
|
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
|
||||||
"415: Unsupported content type {0}",
|
"415: Unsupported content type {0}",
|
||||||
contentType.RawValue));
|
request.ContentType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -11,7 +12,7 @@ using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class handles deserialization of input XML data
|
/// This class handles deserialization of input XML data
|
||||||
|
|
@ -58,21 +59,34 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
get { return _readerQuotas; }
|
get { return _readerQuotas; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool CanRead(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
var contentType = context.ActionContext.HttpContext.Request.ContentType;
|
||||||
|
MediaTypeHeaderValue requestContentType;
|
||||||
|
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SupportedMediaTypes
|
||||||
|
.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads the input XML.
|
/// Reads the input XML.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
||||||
/// <returns>Task which reads the input.</returns>
|
/// <returns>Task which reads the input.</returns>
|
||||||
public async Task ReadAsync(InputFormatterContext context)
|
public async Task<object> ReadAsync(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var request = context.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
if (request.ContentLength == 0)
|
if (request.ContentLength == 0)
|
||||||
{
|
{
|
||||||
context.Model = GetDefaultValueForType(context.Metadata.ModelType);
|
return GetDefaultValueForType(context.ModelType);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Model = await ReadInternal(context);
|
return await ReadInternal(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -107,8 +121,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
private Task<object> ReadInternal(InputFormatterContext context)
|
private Task<object> ReadInternal(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var type = context.Metadata.ModelType;
|
var type = context.ModelType;
|
||||||
var request = context.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
|
|
||||||
using (var xmlReader = CreateXmlReader(new DelegatingStream(request.Body)))
|
using (var xmlReader = CreateXmlReader(new DelegatingStream(request.Body)))
|
||||||
{
|
{
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -11,7 +12,7 @@ using System.Xml;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This class handles deserialization of input XML data
|
/// This class handles deserialization of input XML data
|
||||||
|
|
@ -58,21 +59,34 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
get { return _readerQuotas; }
|
get { return _readerQuotas; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool CanRead(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
var contentType = context.ActionContext.HttpContext.Request.ContentType;
|
||||||
|
MediaTypeHeaderValue requestContentType;
|
||||||
|
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SupportedMediaTypes
|
||||||
|
.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads the input XML.
|
/// Reads the input XML.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
||||||
/// <returns>Task which reads the input.</returns>
|
/// <returns>Task which reads the input.</returns>
|
||||||
public async Task ReadAsync(InputFormatterContext context)
|
public async Task<object> ReadAsync(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var request = context.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
if (request.ContentLength == 0)
|
if (request.ContentLength == 0)
|
||||||
{
|
{
|
||||||
context.Model = GetDefaultValueForType(context.Metadata.ModelType);
|
return GetDefaultValueForType(context.ModelType);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Model = await ReadInternal(context);
|
return await ReadInternal(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -107,8 +121,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
private Task<object> ReadInternal(InputFormatterContext context)
|
private Task<object> ReadInternal(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var type = context.Metadata.ModelType;
|
var type = context.ModelType;
|
||||||
var request = context.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
|
|
||||||
using (var xmlReader = CreateXmlReader(new DelegatingStream(request.Body)))
|
using (var xmlReader = CreateXmlReader(new DelegatingStream(request.Body)))
|
||||||
{
|
{
|
||||||
|
|
@ -51,8 +51,16 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a list of the <see cref="OutputFormatterDescriptor" /> which are used to construct
|
||||||
|
/// a list of <see cref="IOutputFormatter"/> by <see cref="IOutputFormattersProvider"/>.
|
||||||
|
/// </summary>
|
||||||
public List<OutputFormatterDescriptor> OutputFormatters { get; private set; }
|
public List<OutputFormatterDescriptor> OutputFormatters { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a list of the <see cref="InputFormatterDescriptor" /> which are used to construct
|
||||||
|
/// a list of <see cref="IInputFormatter"/> by <see cref="IInputFormatterProvider"/>.
|
||||||
|
/// </summary>
|
||||||
public List<InputFormatterDescriptor> InputFormatters { get; private set; }
|
public List<InputFormatterDescriptor> InputFormatters { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1066,6 +1066,22 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("OutputFormatterNoEncoding"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("OutputFormatterNoEncoding"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No encoding found for input formatter '{0}'. There must be at least one supported encoding registered in order for the formatter to read content.
|
||||||
|
/// </summary>
|
||||||
|
internal static string InputFormatterNoEncoding
|
||||||
|
{
|
||||||
|
get { return GetString("InputFormatterNoEncoding"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No encoding found for input formatter '{0}'. There must be at least one supported encoding registered in order for the formatter to read content.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatInputFormatterNoEncoding(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("InputFormatterNoEncoding"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// No supported media type registered for output formatter '{0}'. There must be at least one supported media type registered in order for the output formatter to write content.
|
/// No supported media type registered for output formatter '{0}'. There must be at least one supported media type registered in order for the output formatter to write content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -81,4 +81,4 @@ namespace Microsoft.AspNet.Mvc
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -315,6 +315,9 @@
|
||||||
<data name="OutputFormatterNoEncoding" xml:space="preserve">
|
<data name="OutputFormatterNoEncoding" xml:space="preserve">
|
||||||
<value>No encoding found for output formatter '{0}'. There must be at least one supported encoding registered in order for the output formatter to write content.</value>
|
<value>No encoding found for output formatter '{0}'. There must be at least one supported encoding registered in order for the output formatter to write content.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="InputFormatterNoEncoding" xml:space="preserve">
|
||||||
|
<value>No encoding found for input formatter '{0}'. There must be at least one supported encoding registered in order for the formatter to read content.</value>
|
||||||
|
</data>
|
||||||
<data name="OutputFormatterNoMediaType" xml:space="preserve">
|
<data name="OutputFormatterNoMediaType" xml:space="preserve">
|
||||||
<value>No supported media type registered for output formatter '{0}'. There must be at least one supported media type registered in order for the output formatter to write content.</value>
|
<value>No supported media type registered for output formatter '{0}'. There must be at least one supported media type registered in order for the output formatter to write content.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
||||||
{
|
{
|
||||||
public static class FormattingUtilities
|
public static class HttpHeaderUtilitites
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Quality factor to indicate a perfect match.
|
/// Quality factor to indicate a perfect match.
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var quality = FormattingUtilities.Match;
|
var quality = HttpHeaderUtilitites.Match;
|
||||||
string qualityStringValue = null;
|
string qualityStringValue = null;
|
||||||
if (mediaTypeHeaderValue.Parameters.TryGetValue("q", out qualityStringValue))
|
if (mediaTypeHeaderValue.Parameters.TryGetValue("q", out qualityStringValue))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,5 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Include="Resources.resx">
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
||||||
var value = inputArray[0].Trim();
|
var value = inputArray[0].Trim();
|
||||||
|
|
||||||
// Unspecified q factor value is equal to a match.
|
// Unspecified q factor value is equal to a match.
|
||||||
var quality = FormattingUtilities.Match;
|
var quality = HttpHeaderUtilitites.Match;
|
||||||
if (inputArray.Length > 1)
|
if (inputArray.Length > 1)
|
||||||
{
|
{
|
||||||
var parameter = inputArray[1].Trim();
|
var parameter = inputArray[1].Trim();
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
|
||||||
{
|
|
||||||
public interface IInputFormatter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the mutable collection of media types supported by this <see cref="JsonInputFormatter"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
IList<MediaTypeHeaderValue> SupportedMediaTypes { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the mutable collection of character encodings supported by this <see cref="JsonInputFormatter"/>
|
|
||||||
/// instance.
|
|
||||||
/// </summary>
|
|
||||||
IList<Encoding> SupportedEncodings { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called during deserialization to read an object from the request.
|
|
||||||
/// </summary>
|
|
||||||
Task ReadAsync(InputFormatterContext context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
|
||||||
{
|
|
||||||
public class InputFormatterContext
|
|
||||||
{
|
|
||||||
public InputFormatterContext([NotNull] HttpContext httpContext,
|
|
||||||
[NotNull] ModelMetadata metadata,
|
|
||||||
[NotNull] ModelStateDictionary modelState)
|
|
||||||
{
|
|
||||||
HttpContext = httpContext;
|
|
||||||
Metadata = metadata;
|
|
||||||
ModelState = modelState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpContext HttpContext { get; private set; }
|
|
||||||
|
|
||||||
public ModelMetadata Metadata { get; private set; }
|
|
||||||
|
|
||||||
public ModelStateDictionary ModelState { get; private set; }
|
|
||||||
|
|
||||||
public object Model { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -74,22 +74,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return GetString("JQuerySyntaxMissingClosingBracket");
|
return GetString("JQuerySyntaxMissingClosingBracket");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// No encoding found for input formatter '{0}'. There must be at least one supported encoding registered in order for the formatter to read content.
|
|
||||||
/// </summary>
|
|
||||||
internal static string MediaTypeFormatterNoEncoding
|
|
||||||
{
|
|
||||||
get { return GetString("MediaTypeFormatterNoEncoding"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// No encoding found for input formatter '{0}'. There must be at least one supported encoding registered in order for the formatter to read content.
|
|
||||||
/// </summary>
|
|
||||||
internal static string FormatMediaTypeFormatterNoEncoding(object p0)
|
|
||||||
{
|
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("MediaTypeFormatterNoEncoding"), p0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Property '{0}' on type '{1}' is invalid. Value-typed properties marked as [Required] must also be marked with [DataMember(IsRequired=true)] to be recognized as required. Consider attributing the declaring type with [DataContract] and the property with [DataMember(IsRequired=true)].
|
/// Property '{0}' on type '{1}' is invalid. Value-typed properties marked as [Required] must also be marked with [DataMember(IsRequired=true)] to be recognized as required. Consider attributing the declaring type with [DataContract] and the property with [DataMember(IsRequired=true)].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,6 @@
|
||||||
<data name="JQuerySyntaxMissingClosingBracket" xml:space="preserve">
|
<data name="JQuerySyntaxMissingClosingBracket" xml:space="preserve">
|
||||||
<value>The key is invalid JQuery syntax because it is missing a closing bracket.</value>
|
<value>The key is invalid JQuery syntax because it is missing a closing bracket.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MediaTypeFormatterNoEncoding" xml:space="preserve">
|
|
||||||
<value>No encoding found for input formatter '{0}'. There must be at least one supported encoding registered in order for the formatter to read content.</value>
|
|
||||||
</data>
|
|
||||||
<data name="MissingDataMemberIsRequired" xml:space="preserve">
|
<data name="MissingDataMemberIsRequired" xml:space="preserve">
|
||||||
<value>Property '{0}' on type '{1}' is invalid. Value-typed properties marked as [Required] must also be marked with [DataMember(IsRequired=true)] to be recognized as required. Consider attributing the declaring type with [DataContract] and the property with [DataMember(IsRequired=true)].</value>
|
<value>Property '{0}' on type '{1}' is invalid. Value-typed properties marked as [Required] must also be marked with [DataMember(IsRequired=true)] to be recognized as required. Consider attributing the declaring type with [DataContract] and the property with [DataMember(IsRequired=true)].</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public class FormValueProviderFactory : IValueProviderFactory
|
public class FormValueProviderFactory : IValueProviderFactory
|
||||||
{
|
{
|
||||||
private static MediaTypeHeaderValue _formEncodedContentType =
|
private static MediaTypeHeaderValue _formEncodedContentType =
|
||||||
MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
|
MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
|
||||||
|
|
||||||
public IValueProvider GetValueProvider([NotNull] ValueProviderFactoryContext context)
|
public IValueProvider GetValueProvider([NotNull] ValueProviderFactoryContext context)
|
||||||
{
|
{
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
MediaTypeHeaderValue requestContentType = null;
|
MediaTypeHeaderValue requestContentType = null;
|
||||||
return MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType) &&
|
return MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType) &&
|
||||||
_formEncodedContentType.IsSubsetOf(requestContentType);
|
_formEncodedContentType.IsSubsetOf(requestContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CultureInfo GetCultureInfo(HttpRequest request)
|
private static CultureInfo GetCultureInfo(HttpRequest request)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class DelegatingStreamTests
|
public class DelegatingStreamTests
|
||||||
{
|
{
|
||||||
|
|
@ -8,14 +8,43 @@ using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class JsonInputFormatterTest
|
public class JsonInputFormatterTest
|
||||||
{
|
{
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/json", true)]
|
||||||
|
[InlineData("application/*", true)]
|
||||||
|
[InlineData("*/*", true)]
|
||||||
|
[InlineData("text/json", true)]
|
||||||
|
[InlineData("text/*", true)]
|
||||||
|
[InlineData("text/xml", false)]
|
||||||
|
[InlineData("application/xml", false)]
|
||||||
|
[InlineData("", false)]
|
||||||
|
[InlineData(null, false)]
|
||||||
|
[InlineData("invalid", false)]
|
||||||
|
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var formatter = new JsonInputFormatter();
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("content");
|
||||||
|
|
||||||
|
var actionContext = GetActionContext(contentBytes, contentType: requestContentType);
|
||||||
|
var formatterContext = new InputFormatterContext(actionContext, typeof(string));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = formatter.CanRead(formatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedCanRead, result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void DefaultMediaType_ReturnsApplicationJson()
|
public void DefaultMediaType_ReturnsApplicationJson()
|
||||||
{
|
{
|
||||||
|
|
@ -48,16 +77,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var formatter = new JsonInputFormatter();
|
var formatter = new JsonInputFormatter();
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var actionContext = GetActionContext(contentBytes);
|
||||||
var modelState = new ModelStateDictionary();
|
var context = new InputFormatterContext(actionContext, type);
|
||||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, type);
|
|
||||||
var context = new InputFormatterContext(httpContext, metadata, modelState);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expected, context.Model);
|
Assert.Equal(expected, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -68,18 +95,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var formatter = new JsonInputFormatter();
|
var formatter = new JsonInputFormatter();
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var actionContext = GetActionContext(contentBytes);
|
||||||
var modelState = new ModelStateDictionary();
|
|
||||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
||||||
var context = new InputFormatterContext(httpContext, metadata, modelState);
|
var context = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var model = Assert.IsType<User>(context.Model);
|
var userModel = Assert.IsType<User>(model);
|
||||||
Assert.Equal("Person Name", model.Name);
|
Assert.Equal("Person Name", userModel.Name);
|
||||||
Assert.Equal(30, model.Age);
|
Assert.Equal(30, userModel.Age);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -90,10 +116,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var formatter = new JsonInputFormatter();
|
var formatter = new JsonInputFormatter();
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var httpContext = GetActionContext(contentBytes);
|
||||||
var modelState = new ModelStateDictionary();
|
|
||||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
||||||
var context = new InputFormatterContext(httpContext, metadata, modelState);
|
var context = new InputFormatterContext(httpContext, metadata.ModelType);
|
||||||
|
|
||||||
// Act and Assert
|
// Act and Assert
|
||||||
await Assert.ThrowsAsync<JsonReaderException>(() => formatter.ReadAsync(context));
|
await Assert.ThrowsAsync<JsonReaderException>(() => formatter.ReadAsync(context));
|
||||||
|
|
@ -107,17 +132,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var formatter = new JsonInputFormatter { CaptureDeserilizationErrors = true };
|
var formatter = new JsonInputFormatter { CaptureDeserilizationErrors = true };
|
||||||
var contentBytes = Encoding.UTF8.GetBytes(content);
|
var contentBytes = Encoding.UTF8.GetBytes(content);
|
||||||
|
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var actionContext = GetActionContext(contentBytes);
|
||||||
var modelState = new ModelStateDictionary();
|
|
||||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(User));
|
||||||
var context = new InputFormatterContext(httpContext, metadata, modelState);
|
var context = new InputFormatterContext(actionContext, metadata.ModelType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
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("Could not convert string to decimal: not-an-age. Path 'Age', line 1, position 39.",
|
||||||
modelState["Age"].Errors[0].Exception.Message);
|
actionContext.ModelState["Age"].Errors[0].Exception.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
private static HttpContext GetHttpContext(byte[] contentBytes,
|
||||||
|
|
@ -125,12 +157,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
var request = new Mock<HttpRequest>();
|
var request = new Mock<HttpRequest>();
|
||||||
var headers = new Mock<IHeaderDictionary>();
|
var headers = new Mock<IHeaderDictionary>();
|
||||||
headers.SetupGet(h => h["Content-Type"]).Returns(contentType);
|
|
||||||
request.SetupGet(r => r.Headers).Returns(headers.Object);
|
request.SetupGet(r => r.Headers).Returns(headers.Object);
|
||||||
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
|
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
|
||||||
|
request.SetupGet(f => f.ContentType).Returns(contentType);
|
||||||
|
|
||||||
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.Request).Returns(request.Object);
|
||||||
return httpContext.Object;
|
return httpContext.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -10,10 +10,11 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class DataContractSerializerInputFormatterTests
|
public class DataContractSerializerInputFormatterTests
|
||||||
{
|
{
|
||||||
|
|
@ -43,6 +44,33 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public TestLevelOne TestOne { get; set; }
|
public TestLevelOne TestOne { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/xml", true)]
|
||||||
|
[InlineData("application/*", true)]
|
||||||
|
[InlineData("*/*", true)]
|
||||||
|
[InlineData("text/xml", true)]
|
||||||
|
[InlineData("text/*", true)]
|
||||||
|
[InlineData("text/json", false)]
|
||||||
|
[InlineData("application/json", false)]
|
||||||
|
[InlineData("", false)]
|
||||||
|
[InlineData(null, false)]
|
||||||
|
[InlineData("invalid", false)]
|
||||||
|
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var formatter = new XmlDataContractSerializerInputFormatter();
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("content");
|
||||||
|
|
||||||
|
var actionContext = GetActionContext(contentBytes, contentType: requestContentType);
|
||||||
|
var formatterContext = new InputFormatterContext(actionContext, typeof(string));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = formatter.CanRead(formatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedCanRead, result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void XmlDataContractSerializerFormatterHasProperSuppportedMediaTypes()
|
public void XmlDataContractSerializerFormatterHasProperSuppportedMediaTypes()
|
||||||
{
|
{
|
||||||
|
|
@ -85,15 +113,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<TestLevelOne>(context.Model);
|
Assert.IsType<TestLevelOne>(model);
|
||||||
|
|
||||||
var model = context.Model as TestLevelOne;
|
var levelOneModel = model as TestLevelOne;
|
||||||
Assert.Equal(expectedInt, model.SampleInt);
|
Assert.Equal(expectedInt, levelOneModel.SampleInt);
|
||||||
Assert.Equal(expectedString, model.sampleString);
|
Assert.Equal(expectedString, levelOneModel.sampleString);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -114,16 +142,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<TestLevelTwo>(context.Model);
|
Assert.IsType<TestLevelTwo>(model);
|
||||||
|
|
||||||
var model = context.Model as TestLevelTwo;
|
var levelTwoModel = model as TestLevelTwo;
|
||||||
Assert.Equal(expectedLevelTwoString, model.SampleString);
|
Assert.Equal(expectedLevelTwoString, levelTwoModel.SampleString);
|
||||||
Assert.Equal(expectedInt, model.TestOne.SampleInt);
|
Assert.Equal(expectedInt, levelTwoModel.TestOne.SampleInt);
|
||||||
Assert.Equal(expectedString, model.TestOne.sampleString);
|
Assert.Equal(expectedString, levelTwoModel.TestOne.sampleString);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -141,13 +169,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<DummyClass>(context.Model);
|
Assert.IsType<DummyClass>(model);
|
||||||
var model = context.Model as DummyClass;
|
var dummyModel = model as DummyClass;
|
||||||
Assert.Equal(expectedInt, model.SampleInt);
|
Assert.Equal(expectedInt, dummyModel.SampleInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -205,11 +233,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
|
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.True(context.HttpContext.Request.Body.CanRead);
|
Assert.True(context.ActionContext.HttpContext.Request.Body.CanRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -254,14 +282,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
var model = context.Model as TestLevelTwo;
|
var levelTwoModel = model as TestLevelTwo;
|
||||||
Buffer.BlockCopy(sampleStringBytes, 0, expectedBytes, 0, sampleStringBytes.Length);
|
Buffer.BlockCopy(sampleStringBytes, 0, expectedBytes, 0, sampleStringBytes.Length);
|
||||||
Buffer.BlockCopy(bom, 0, expectedBytes, sampleStringBytes.Length, bom.Length);
|
Buffer.BlockCopy(bom, 0, expectedBytes, sampleStringBytes.Length, bom.Length);
|
||||||
Assert.Equal(expectedBytes, Encoding.UTF8.GetBytes(model.SampleString));
|
Assert.Equal(expectedBytes, Encoding.UTF8.GetBytes(levelTwoModel.SampleString));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -280,36 +308,43 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<TestLevelOne>(context.Model);
|
Assert.IsType<TestLevelOne>(model);
|
||||||
|
|
||||||
var model = context.Model as TestLevelOne;
|
var levelOneModel = model as TestLevelOne;
|
||||||
Assert.Equal(expectedInt, model.SampleInt);
|
Assert.Equal(expectedInt, levelOneModel.SampleInt);
|
||||||
Assert.Equal(expectedString, model.sampleString);
|
Assert.Equal(expectedString, levelOneModel.sampleString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
|
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
|
||||||
{
|
{
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var actionContext = GetActionContext(contentBytes);
|
||||||
var modelState = new ModelStateDictionary();
|
|
||||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, modelType);
|
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, modelType);
|
||||||
return new InputFormatterContext(httpContext, metadata, modelState);
|
return new InputFormatterContext(actionContext, metadata.ModelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
private static HttpContext GetHttpContext(byte[] contentBytes,
|
||||||
string contentType = "application/xml")
|
string contentType = "application/xml")
|
||||||
{
|
{
|
||||||
var request = new Mock<HttpRequest>();
|
var request = new Mock<HttpRequest>();
|
||||||
var headers = new Mock<IHeaderDictionary>();
|
var headers = new Mock<IHeaderDictionary>();
|
||||||
headers.SetupGet(h => h["Content-Type"]).Returns(contentType);
|
|
||||||
request.SetupGet(r => r.Headers).Returns(headers.Object);
|
request.SetupGet(r => r.Headers).Returns(headers.Object);
|
||||||
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
|
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
|
||||||
|
request.SetupGet(f => f.ContentType).Returns(contentType);
|
||||||
|
|
||||||
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.Request).Returns(request.Object);
|
||||||
return httpContext.Object;
|
return httpContext.Object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,10 +9,11 @@ using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class XmlSerializerInputFormatterTests
|
public class XmlSerializerInputFormatterTests
|
||||||
{
|
{
|
||||||
|
|
@ -34,6 +35,33 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
public TestLevelOne TestOne { get; set; }
|
public TestLevelOne TestOne { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("application/xml", true)]
|
||||||
|
[InlineData("application/*", true)]
|
||||||
|
[InlineData("*/*", true)]
|
||||||
|
[InlineData("text/xml", true)]
|
||||||
|
[InlineData("text/*", true)]
|
||||||
|
[InlineData("text/json", false)]
|
||||||
|
[InlineData("application/json", false)]
|
||||||
|
[InlineData("", false)]
|
||||||
|
[InlineData("invalid", false)]
|
||||||
|
[InlineData(null, false)]
|
||||||
|
public void CanRead_ReturnsTrueForAnySupportedContentType(string requestContentType, bool expectedCanRead)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var formatter = new XmlSerializerInputFormatter();
|
||||||
|
var contentBytes = Encoding.UTF8.GetBytes("content");
|
||||||
|
|
||||||
|
var actionContext = GetActionContext(contentBytes, contentType: requestContentType);
|
||||||
|
var formatterContext = new InputFormatterContext(actionContext, typeof(string));
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = formatter.CanRead(formatterContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expectedCanRead, result);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void XmlSerializerFormatterHasProperSuppportedMediaTypes()
|
public void XmlSerializerFormatterHasProperSuppportedMediaTypes()
|
||||||
{
|
{
|
||||||
|
|
@ -78,16 +106,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<TestLevelOne>(context.Model);
|
Assert.IsType<TestLevelOne>(model);
|
||||||
|
|
||||||
var model = context.Model as TestLevelOne;
|
var levelOneModel = model as TestLevelOne;
|
||||||
Assert.Equal(expectedInt, model.SampleInt);
|
Assert.Equal(expectedInt, levelOneModel.SampleInt);
|
||||||
Assert.Equal(expectedString, model.sampleString);
|
Assert.Equal(expectedString, levelOneModel.sampleString);
|
||||||
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), model.SampleDate);
|
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc),
|
||||||
|
levelOneModel.SampleDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -110,17 +139,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<TestLevelTwo>(context.Model);
|
Assert.IsType<TestLevelTwo>(model);
|
||||||
|
|
||||||
var model = context.Model as TestLevelTwo;
|
var levelTwoModel = model as TestLevelTwo;
|
||||||
Assert.Equal(expectedLevelTwoString, model.SampleString);
|
Assert.Equal(expectedLevelTwoString, levelTwoModel.SampleString);
|
||||||
Assert.Equal(expectedInt, model.TestOne.SampleInt);
|
Assert.Equal(expectedInt, levelTwoModel.TestOne.SampleInt);
|
||||||
Assert.Equal(expectedString, model.TestOne.sampleString);
|
Assert.Equal(expectedString, levelTwoModel.TestOne.sampleString);
|
||||||
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), model.TestOne.SampleDate);
|
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc),
|
||||||
|
levelTwoModel.TestOne.SampleDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -138,13 +168,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<DummyClass>(context.Model);
|
Assert.IsType<DummyClass>(model);
|
||||||
var model = context.Model as DummyClass;
|
var dummyModel = model as DummyClass;
|
||||||
Assert.Equal(expectedInt, model.SampleInt);
|
Assert.Equal(expectedInt, dummyModel.SampleInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -206,11 +236,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
|
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.True(context.HttpContext.Request.Body.CanRead);
|
Assert.True(context.ActionContext.HttpContext.Request.Body.CanRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -255,14 +285,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
var model = context.Model as TestLevelTwo;
|
var levelTwoModel = model as TestLevelTwo;
|
||||||
Buffer.BlockCopy(sampleStringBytes, 0, expectedBytes, 0, sampleStringBytes.Length);
|
Buffer.BlockCopy(sampleStringBytes, 0, expectedBytes, 0, sampleStringBytes.Length);
|
||||||
Buffer.BlockCopy(bom, 0, expectedBytes, sampleStringBytes.Length, bom.Length);
|
Buffer.BlockCopy(bom, 0, expectedBytes, sampleStringBytes.Length, bom.Length);
|
||||||
Assert.Equal(expectedBytes, Encoding.UTF8.GetBytes(model.SampleString));
|
Assert.Equal(expectedBytes, Encoding.UTF8.GetBytes(levelTwoModel.SampleString));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -283,37 +313,44 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await formatter.ReadAsync(context);
|
var model = await formatter.ReadAsync(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(context.Model);
|
Assert.NotNull(model);
|
||||||
Assert.IsType<TestLevelOne>(context.Model);
|
Assert.IsType<TestLevelOne>(model);
|
||||||
|
|
||||||
var model = context.Model as TestLevelOne;
|
var levelOneModel = model as TestLevelOne;
|
||||||
Assert.Equal(expectedInt, model.SampleInt);
|
Assert.Equal(expectedInt, levelOneModel.SampleInt);
|
||||||
Assert.Equal(expectedString, model.sampleString);
|
Assert.Equal(expectedString, levelOneModel.sampleString);
|
||||||
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), model.SampleDate);
|
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), levelOneModel.SampleDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
|
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
|
||||||
{
|
{
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var actionContext = GetActionContext(contentBytes);
|
||||||
var modelState = new ModelStateDictionary();
|
|
||||||
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, modelType);
|
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, modelType);
|
||||||
return new InputFormatterContext(httpContext, metadata, modelState);
|
return new InputFormatterContext(actionContext, metadata.ModelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
private static HttpContext GetHttpContext(byte[] contentBytes,
|
||||||
string contentType = "application/xml")
|
string contentType = "application/xml")
|
||||||
{
|
{
|
||||||
var request = new Mock<HttpRequest>();
|
var request = new Mock<HttpRequest>();
|
||||||
var headers = new Mock<IHeaderDictionary>();
|
var headers = new Mock<IHeaderDictionary>();
|
||||||
headers.SetupGet(h => h["Content-Type"]).Returns(contentType);
|
|
||||||
request.SetupGet(r => r.Headers).Returns(headers.Object);
|
request.SetupGet(r => r.Headers).Returns(headers.Object);
|
||||||
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
|
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
|
||||||
|
request.SetupGet(f => f.ContentType).Returns(contentType);
|
||||||
|
|
||||||
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.Request).Returns(request.Object);
|
||||||
return httpContext.Object;
|
return httpContext.Object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.OptionDescriptors;
|
using Microsoft.AspNet.Mvc.OptionDescriptors;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -14,12 +17,53 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = "The type 'System.String' must derive from " +
|
var expected = "The type 'System.String' must derive from " +
|
||||||
"'Microsoft.AspNet.Mvc.ModelBinding.IInputFormatter'.";
|
"'Microsoft.AspNet.Mvc.IInputFormatter'.";
|
||||||
|
|
||||||
var type = typeof(string);
|
var type = typeof(string);
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
ExceptionAssert.ThrowsArgument(() => new InputFormatterDescriptor(type), "type", expected);
|
ExceptionAssert.ThrowsArgument(() => new InputFormatterDescriptor(type), "type", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ConstructorSets_InputFormatterType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var type = typeof(TestInputFormatter);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptor = new InputFormatterDescriptor(type);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(type, descriptor.OptionType);
|
||||||
|
Assert.Null(descriptor.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ConstructorSets_InputFormatterInstanceAndType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var testFormatter = new TestInputFormatter();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptor = new InputFormatterDescriptor(testFormatter);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(testFormatter, descriptor.Instance);
|
||||||
|
Assert.Equal(testFormatter.GetType(), descriptor.OptionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestInputFormatter : IInputFormatter
|
||||||
|
{
|
||||||
|
public bool CanRead(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<object> ReadAsync(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
|
||||||
using Microsoft.AspNet.Mvc.OptionDescriptors;
|
using Microsoft.AspNet.Mvc.OptionDescriptors;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -21,5 +24,46 @@ namespace Microsoft.AspNet.Mvc.Core
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
ExceptionAssert.ThrowsArgument(() => new OutputFormatterDescriptor(type), "type", expected);
|
ExceptionAssert.ThrowsArgument(() => new OutputFormatterDescriptor(type), "type", expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ConstructorSets_OutputFormatterType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var type = typeof(TestOutputFormatter);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptor = new OutputFormatterDescriptor(type);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(type, descriptor.OptionType);
|
||||||
|
Assert.Null(descriptor.Instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ConstructorSets_OutputFormatterInsnaceAndType()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var testFormatter = new TestOutputFormatter();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var descriptor = new OutputFormatterDescriptor(testFormatter);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Same(testFormatter, descriptor.Instance);
|
||||||
|
Assert.Equal(testFormatter.GetType(), descriptor.OptionType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestOutputFormatter : IOutputFormatter
|
||||||
|
{
|
||||||
|
public bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task WriteAsync(OutputFormatterContext context)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -37,8 +37,13 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal(sampleInputInt.ToString(), await response.ReadBodyAsStringAsync());
|
Assert.Equal(sampleInputInt.ToString(), await response.ReadBodyAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Theory]
|
||||||
public async Task JsonInputFormatter_IsSelectedForJsonRequest()
|
[InlineData("application/json")]
|
||||||
|
[InlineData("application/*")]
|
||||||
|
[InlineData("*/*")]
|
||||||
|
[InlineData("text/json")]
|
||||||
|
[InlineData("text/*")]
|
||||||
|
public async Task JsonInputFormatter_IsSelectedForJsonRequest(string requestContentType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var server = TestServer.Create(_services, _app);
|
var server = TestServer.Create(_services, _app);
|
||||||
|
|
@ -47,13 +52,33 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
var input = "{\"SampleInt\":10}";
|
var input = "{\"SampleInt\":10}";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var response = await client.PostAsync("http://localhost/Home/Index", input, "application/json");
|
var response = await client.PostAsync("http://localhost/Home/Index", input, requestContentType);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Equal(200, response.StatusCode);
|
Assert.Equal(200, response.StatusCode);
|
||||||
Assert.Equal(sampleInputInt.ToString(), await response.ReadBodyAsStringAsync());
|
Assert.Equal(sampleInputInt.ToString(), await response.ReadBodyAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("")]
|
||||||
|
[InlineData(null)]
|
||||||
|
[InlineData("invalid")]
|
||||||
|
public async Task JsonInputFormatter_IsNotSelectedForNonJsonRequests(string requestContentType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.Handler;
|
||||||
|
var input = "{\"SampleInt\":10}";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>
|
||||||
|
(() => client.PostAsync("http://localhost/Home/CheckIfDummyIsNull", input, requestContentType));
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
// TODO: Change the validation after https://github.com/aspnet/Mvc/issues/458 is fixed.
|
||||||
|
Assert.Equal("415: Unsupported content type " + requestContentType, ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: By default XmlSerializerInputFormatter is called because of the order in which
|
// TODO: By default XmlSerializerInputFormatter is called because of the order in which
|
||||||
// the formatters are registered. Add a test to call into DataContractSerializerInputFormatter.
|
// the formatters are registered. Add a test to call into DataContractSerializerInputFormatter.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
||||||
null,
|
null,
|
||||||
MediaTypeHeaderValueRange.AllMediaRange,
|
MediaTypeHeaderValueRange.AllMediaRange,
|
||||||
new Dictionary<string, string>(),
|
new Dictionary<string, string>(),
|
||||||
FormattingUtilities.Match,
|
HttpHeaderUtilitites.Match,
|
||||||
"*/*"
|
"*/*"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
||||||
"utf-8",
|
"utf-8",
|
||||||
MediaTypeHeaderValueRange.SubtypeMediaRange,
|
MediaTypeHeaderValueRange.SubtypeMediaRange,
|
||||||
new Dictionary<string, string>() { { "charset", "utf-8" }, { "foo", "bar" } },
|
new Dictionary<string, string>() { { "charset", "utf-8" }, { "foo", "bar" } },
|
||||||
FormattingUtilities.Match,
|
HttpHeaderUtilitites.Match,
|
||||||
"text/*;charset=utf-8;foo=bar",
|
"text/*;charset=utf-8;foo=bar",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
||||||
"utf-8",
|
"utf-8",
|
||||||
MediaTypeHeaderValueRange.None,
|
MediaTypeHeaderValueRange.None,
|
||||||
new Dictionary<string, string>() { { "charset", "utf-8" }, { "foo", "bar" }, { "q", "0.0" } },
|
new Dictionary<string, string>() { { "charset", "utf-8" }, { "foo", "bar" }, { "q", "0.0" } },
|
||||||
FormattingUtilities.NoMatch,
|
HttpHeaderUtilitites.NoMatch,
|
||||||
"text/plain;charset=utf-8;foo=bar;q=0.0",
|
"text/plain;charset=utf-8;foo=bar;q=0.0",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
|
||||||
public class StringWithQualityHeaderValueParsingTests
|
public class StringWithQualityHeaderValueParsingTests
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("*", FormattingUtilities.Match, "*")]
|
[InlineData("*", HttpHeaderUtilitites.Match, "*")]
|
||||||
[InlineData("*", 0.7, "*;q=.7")]
|
[InlineData("*", 0.7, "*;q=.7")]
|
||||||
[InlineData("iso-8859-5", FormattingUtilities.Match, "iso-8859-5")]
|
[InlineData("iso-8859-5", HttpHeaderUtilitites.Match, "iso-8859-5")]
|
||||||
[InlineData("unicode-1-1", 0.8, "unicode-1-1;q=0.8")]
|
[InlineData("unicode-1-1", 0.8, "unicode-1-1;q=0.8")]
|
||||||
[InlineData("unicode-1-1", 0.8, "unicode-1-1;q =0.8")]
|
[InlineData("unicode-1-1", 0.8, "unicode-1-1;q =0.8")]
|
||||||
[InlineData("unicode-1-1", 0.8, "unicode-1-1;q = 0.8")]
|
[InlineData("unicode-1-1", 0.8, "unicode-1-1;q = 0.8")]
|
||||||
|
|
|
||||||
|
|
@ -18,5 +18,11 @@ namespace FormatterWebSite.Controllers
|
||||||
{
|
{
|
||||||
return new DummyClass { SampleInt = sampleInput };
|
return new DummyClass { SampleInt = sampleInput };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public bool CheckIfDummyIsNull([FromBody] DummyClass dummy)
|
||||||
|
{
|
||||||
|
return dummy != null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue