Clean up `ModelBindingResult` constructor calls and related comments
- use named parameters more often - add more comments about returned `ModelBindingResult` - clean up `ModelBindingResult` doc comments - cleanup `using`s Nits: - cleanup trailing whitespace - change `retVal` -> `result` in `KeyValuePairModelBinderTest`
This commit is contained in:
parent
103538b889
commit
64c8a6fa40
|
|
@ -6,8 +6,6 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
|
||||||
using Microsoft.Framework.DependencyInjection;
|
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
@ -57,6 +55,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var unsupportedContentType = Resources.FormatUnsupportedContentType(
|
var unsupportedContentType = Resources.FormatUnsupportedContentType(
|
||||||
bindingContext.OperationBindingContext.HttpContext.Request.ContentType);
|
bindingContext.OperationBindingContext.HttpContext.Request.ContentType);
|
||||||
bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType);
|
bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType);
|
||||||
|
|
||||||
|
// This model binder is the only handler for the Body binding source.
|
||||||
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,9 +70,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
model = GetDefaultValueForType(bindingContext.ModelType);
|
model = GetDefaultValueForType(bindingContext.ModelType);
|
||||||
bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
|
bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);
|
||||||
|
|
||||||
|
// This model binder is the only handler for the Body binding source.
|
||||||
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
// key is empty to ensure that the model name is not used as a prefix for validation.
|
// key is empty to ensure that the model name is not used as a prefix for validation.
|
||||||
return new ModelBindingResult(model, key: string.Empty, isModelSet: true);
|
return new ModelBindingResult(model, key: string.Empty, isModelSet: true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
|
var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
|
||||||
var model = requestServices.GetRequiredService(bindingContext.ModelType);
|
var model = requestServices.GetRequiredService(bindingContext.ModelType);
|
||||||
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, true));
|
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
|
var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
|
||||||
var createFactory = _typeActivatorCache.GetOrAdd(bindingContext.BinderType, _createFactory);
|
var createFactory = _typeActivatorCache.GetOrAdd(bindingContext.BinderType, _createFactory);
|
||||||
var instance = createFactory(requestServices, arguments: null);
|
var instance = createFactory(requestServices, arguments: null);
|
||||||
|
|
||||||
var modelBinder = instance as IModelBinder;
|
var modelBinder = instance as IModelBinder;
|
||||||
if (modelBinder == null)
|
if (modelBinder == null)
|
||||||
{
|
{
|
||||||
|
|
@ -54,12 +54,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
var result = await modelBinder.BindModelAsync(bindingContext);
|
var result = await modelBinder.BindModelAsync(bindingContext);
|
||||||
|
|
||||||
var modelBindingResult = result != null ?
|
var modelBindingResult = result != null ?
|
||||||
new ModelBindingResult(result.Model, result.Key, result.IsModelSet) :
|
new ModelBindingResult(result.Model, result.Key, result.IsModelSet) :
|
||||||
new ModelBindingResult(null, bindingContext.ModelName, false);
|
new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
|
|
||||||
// return a non null modelbinding result here, because this binder will handle all cases where the
|
// A model binder was specified by metadata and this binder handles all such cases.
|
||||||
// model binder is specified by metadata.
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return modelBindingResult;
|
return modelBindingResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// A <see cref="Task"/> which will complete when model binding has completed.
|
/// A <see cref="Task"/> which will complete when model binding has completed.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// Other model binders will never run if this method is called. Return <c>null</c> to skip other model binders
|
||||||
|
/// but allow higher-level handling e.g. falling back to empty prefix.
|
||||||
|
/// </remarks>
|
||||||
protected abstract Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext);
|
protected abstract Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -74,13 +78,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
var result = await BindModelCoreAsync(context);
|
var result = await BindModelCoreAsync(context);
|
||||||
|
|
||||||
var modelBindingResult =
|
var modelBindingResult =
|
||||||
result != null ?
|
result != null ?
|
||||||
new ModelBindingResult(result.Model, result.Key, result.IsModelSet) :
|
new ModelBindingResult(result.Model, result.Key, result.IsModelSet) :
|
||||||
new ModelBindingResult(null, context.ModelName, false);
|
new ModelBindingResult(model: null, key: context.ModelName, isModelSet: false);
|
||||||
|
|
||||||
// Prevent other model binders from running because this model binder is the only handler for
|
// This model binder is the only handler for its binding source.
|
||||||
// its binding source.
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return modelBindingResult;
|
return modelBindingResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
@ -40,13 +39,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var model = Convert.FromBase64String(value);
|
var model = Convert.FromBase64String(value);
|
||||||
return new ModelBindingResult(model, bindingContext.ModelName, true);
|
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
|
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Matched the type (byte[]) only this binder supports.
|
||||||
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
if (bindingContext.ModelType == typeof(CancellationToken))
|
if (bindingContext.ModelType == typeof(CancellationToken))
|
||||||
{
|
{
|
||||||
var model = bindingContext.OperationBindingContext.HttpContext.RequestAborted;
|
var model = bindingContext.OperationBindingContext.HttpContext.RequestAborted;
|
||||||
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, true));
|
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult<ModelBindingResult>(null);
|
return Task.FromResult<ModelBindingResult>(null);
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
BindComplexCollection(bindingContext);
|
BindComplexCollection(bindingContext);
|
||||||
var boundCollection = await bindCollectionTask;
|
var boundCollection = await bindCollectionTask;
|
||||||
var model = GetModel(boundCollection);
|
var model = GetModel(boundCollection);
|
||||||
return new ModelBindingResult(model, bindingContext.ModelName, true);
|
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used when the ValueProvider contains the collection to be bound as a single element, e.g. the raw value
|
// Used when the ValueProvider contains the collection to be bound as a single element, e.g. the raw value
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
@ -34,14 +33,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
public virtual async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
|
public virtual async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
|
||||||
{
|
{
|
||||||
var newBindingContext = CreateNewBindingContext(bindingContext,
|
var newBindingContext = CreateNewBindingContext(bindingContext, bindingContext.ModelName);
|
||||||
bindingContext.ModelName);
|
|
||||||
|
|
||||||
var modelBindingResult = await TryBind(newBindingContext);
|
var modelBindingResult = await TryBind(newBindingContext);
|
||||||
if (modelBindingResult == null && !string.IsNullOrEmpty(bindingContext.ModelName)
|
|
||||||
&& bindingContext.FallbackToEmptyPrefix)
|
if (modelBindingResult == null &&
|
||||||
|
bindingContext.FallbackToEmptyPrefix &&
|
||||||
|
!string.IsNullOrEmpty(bindingContext.ModelName))
|
||||||
{
|
{
|
||||||
// fallback to empty prefix?
|
// Fall back to empty prefix.
|
||||||
newBindingContext = CreateNewBindingContext(bindingContext,
|
newBindingContext = CreateNewBindingContext(bindingContext,
|
||||||
modelName: string.Empty);
|
modelName: string.Empty);
|
||||||
modelBindingResult = await TryBind(newBindingContext);
|
modelBindingResult = await TryBind(newBindingContext);
|
||||||
|
|
@ -75,13 +74,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// {
|
// {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// In this case, for the model parameter the key would be SimpleType instead of model.SimpleType.
|
// In this case, for the model parameter the key would be SimpleType instead of model.SimpleType.
|
||||||
// (i.e here the prefix for the model key is empty).
|
// (i.e here the prefix for the model key is empty).
|
||||||
// For the id parameter the key would be id.
|
// For the id parameter the key would be id.
|
||||||
return modelBindingResult;
|
return modelBindingResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fall through to update the ModelBindingResult's key.
|
||||||
return new ModelBindingResult(
|
return new ModelBindingResult(
|
||||||
modelBindingResult.Model,
|
modelBindingResult.Model,
|
||||||
bindingContext.ModelName,
|
bindingContext.ModelName,
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
model = new FormCollection(new Dictionary<string, string[]>());
|
model = new FormCollection(new Dictionary<string, string[]>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ModelBindingResult(model, bindingContext.ModelName, true);
|
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -25,14 +25,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
var postedFiles = await GetFormFilesAsync(bindingContext);
|
var postedFiles = await GetFormFilesAsync(bindingContext);
|
||||||
var value = postedFiles.FirstOrDefault();
|
var value = postedFiles.FirstOrDefault();
|
||||||
return new ModelBindingResult(value, bindingContext.ModelName, value != null);
|
return new ModelBindingResult(value, bindingContext.ModelName, isModelSet: value != null);
|
||||||
}
|
}
|
||||||
else if (typeof(IEnumerable<IFormFile>).GetTypeInfo().IsAssignableFrom(
|
else if (typeof(IEnumerable<IFormFile>).GetTypeInfo().IsAssignableFrom(
|
||||||
bindingContext.ModelType.GetTypeInfo()))
|
bindingContext.ModelType.GetTypeInfo()))
|
||||||
{
|
{
|
||||||
var postedFiles = await GetFormFilesAsync(bindingContext);
|
var postedFiles = await GetFormFilesAsync(bindingContext);
|
||||||
var value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles);
|
var value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles);
|
||||||
return new ModelBindingResult(value, bindingContext.ModelName, value != null);
|
return new ModelBindingResult(value, bindingContext.ModelName, isModelSet: value != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
var modelBindingResult = result != null ?
|
var modelBindingResult = result != null ?
|
||||||
new ModelBindingResult(result.Model, result.Key, result.IsModelSet) :
|
new ModelBindingResult(result.Model, result.Key, result.IsModelSet) :
|
||||||
new ModelBindingResult(null, bindingContext.ModelName, false);
|
new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
|
|
||||||
// Was able to resolve a binder type, hence we should tell the model binding system to return
|
// Were able to resolve a binder type.
|
||||||
// true so that none of the other model binders participate.
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return modelBindingResult;
|
return modelBindingResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, model != null));
|
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, isModelSet: model != null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// 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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||||
|
|
||||||
|
|
@ -25,6 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
ModelBindingHelper.CastOrDefault<TKey>(keyResult.Model),
|
ModelBindingHelper.CastOrDefault<TKey>(keyResult.Model),
|
||||||
ModelBindingHelper.CastOrDefault<TValue>(valueResult.Model));
|
ModelBindingHelper.CastOrDefault<TValue>(valueResult.Model));
|
||||||
|
|
||||||
|
// Success
|
||||||
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true);
|
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true);
|
||||||
}
|
}
|
||||||
else if (!keyResult.IsModelSet && valueResult.IsModelSet)
|
else if (!keyResult.IsModelSet && valueResult.IsModelSet)
|
||||||
|
|
@ -32,6 +32,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
bindingContext.ModelState.TryAddModelError(
|
bindingContext.ModelState.TryAddModelError(
|
||||||
keyResult.Key,
|
keyResult.Key,
|
||||||
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
||||||
|
|
||||||
|
// Were able to get some data for this model.
|
||||||
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
}
|
}
|
||||||
else if (keyResult.IsModelSet && !valueResult.IsModelSet)
|
else if (keyResult.IsModelSet && !valueResult.IsModelSet)
|
||||||
|
|
@ -39,10 +42,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
bindingContext.ModelState.TryAddModelError(
|
bindingContext.ModelState.TryAddModelError(
|
||||||
valueResult.Key,
|
valueResult.Key,
|
||||||
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
Resources.KeyValuePair_BothKeyAndValueMustBePresent);
|
||||||
|
|
||||||
|
// Were able to get some data for this model.
|
||||||
|
// Always tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Caller (GenericModelBinder) was able to resolve a binder type and will create a ModelBindingResult
|
||||||
|
// that exits current ModelBinding loop.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -58,16 +66,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
parentBindingContext,
|
parentBindingContext,
|
||||||
propertyModelName,
|
propertyModelName,
|
||||||
propertyModelMetadata);
|
propertyModelMetadata);
|
||||||
|
|
||||||
propertyBindingContext.BinderModelName = propertyModelMetadata.BinderModelName;
|
propertyBindingContext.BinderModelName = propertyModelMetadata.BinderModelName;
|
||||||
|
|
||||||
var modelBindingResult =
|
var modelBindingResult = await propertyBindingContext.OperationBindingContext.ModelBinder.BindModelAsync(
|
||||||
await propertyBindingContext.OperationBindingContext.ModelBinder.BindModelAsync(propertyBindingContext);
|
propertyBindingContext);
|
||||||
if (modelBindingResult != null)
|
if (modelBindingResult != null)
|
||||||
{
|
{
|
||||||
return modelBindingResult;
|
return modelBindingResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Always return a ModelBindingResult to avoid an NRE in BindModelAsync.
|
||||||
return new ModelBindingResult(model: default(TModel), key: propertyModelName, isModelSet: false);
|
return new ModelBindingResult(model: default(TModel), key: propertyModelName, isModelSet: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// post-processing, e.g. property setters and hooking up validation
|
// post-processing, e.g. property setters and hooking up validation
|
||||||
ProcessDto(bindingContext, (ComplexModelDto)result.Model);
|
ProcessDto(bindingContext, (ComplexModelDto)result.Model);
|
||||||
return new ModelBindingResult(
|
return new ModelBindingResult(
|
||||||
bindingContext.Model,
|
bindingContext.Model,
|
||||||
bindingContext.ModelName,
|
bindingContext.ModelName,
|
||||||
isModelSet: true);
|
isModelSet: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,6 +53,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
internal async Task<bool> CanCreateModel(MutableObjectBinderContext context)
|
internal async Task<bool> CanCreateModel(MutableObjectBinderContext context)
|
||||||
{
|
{
|
||||||
var bindingContext = context.ModelBindingContext;
|
var bindingContext = context.ModelBindingContext;
|
||||||
|
|
||||||
var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
|
var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
|
||||||
var hasExplicitAlias = bindingContext.BinderModelName != null;
|
var hasExplicitAlias = bindingContext.BinderModelName != null;
|
||||||
|
|
||||||
|
|
@ -117,7 +118,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// However, because a property might specify a custom binding source ([FromForm]), it's not correct
|
// However, because a property might specify a custom binding source ([FromForm]), it's not correct
|
||||||
// for us to just try bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName),
|
// for us to just try bindingContext.ValueProvider.ContainsPrefixAsync(bindingContext.ModelName),
|
||||||
// because that may include ALL value providers - that would lead us to mistakenly create the model
|
// because that may include ALL value providers - that would lead us to mistakenly create the model
|
||||||
// when the data is coming from a source we should use (ex: value found in query string, but the
|
// when the data is coming from a source we should use (ex: value found in query string, but the
|
||||||
// model has [FromForm]).
|
// model has [FromForm]).
|
||||||
//
|
//
|
||||||
// To do this we need to enumerate the properties, and see which of them provide a binding source
|
// To do this we need to enumerate the properties, and see which of them provide a binding source
|
||||||
|
|
@ -133,7 +134,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// If a property does not have a binding source, then it's fair game for any value provider.
|
// If a property does not have a binding source, then it's fair game for any value provider.
|
||||||
//
|
//
|
||||||
// If any property meets the above conditions and has a value from valueproviders, then we'll
|
// If any property meets the above conditions and has a value from valueproviders, then we'll
|
||||||
// create the model and try to bind it. OR if ALL properties of the model have a greedy source,
|
// create the model and try to bind it. OR if ALL properties of the model have a greedy source,
|
||||||
// then we go ahead and create it.
|
// then we go ahead and create it.
|
||||||
//
|
//
|
||||||
var isAnyPropertyEnabledForValueProviderBasedBinding = false;
|
var isAnyPropertyEnabledForValueProviderBasedBinding = false;
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
newModel = valueProviderResult.ConvertTo(bindingContext.ModelType);
|
newModel = valueProviderResult.ConvertTo(bindingContext.ModelType);
|
||||||
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
|
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
|
||||||
return new ModelBindingResult(newModel, bindingContext.ModelName, true);
|
return new ModelBindingResult(newModel, bindingContext.ModelName, isModelSet: true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
|
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ModelBindingResult(null, bindingContext.ModelName, false);
|
// Were able to find a converter for the type but conversion failed.
|
||||||
|
// Tell the model binding system to skip other model binders i.e. return non-null.
|
||||||
|
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
|
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
|
||||||
var model = valueProviderResult.RawValue;
|
var model = valueProviderResult.RawValue;
|
||||||
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model);
|
ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model);
|
||||||
return new ModelBindingResult(model, bindingContext.ModelName, true);
|
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<ValueProviderResult> GetCompatibleValueProviderResult(ModelBindingContext context)
|
internal static async Task<ValueProviderResult> GetCompatibleValueProviderResult(ModelBindingContext context)
|
||||||
|
|
|
||||||
|
|
@ -23,22 +23,28 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the model associated with this context.
|
/// Gets the model associated with this context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object Model { get; }
|
public object Model { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the model name which was used to bind the model.
|
/// <para>
|
||||||
///
|
/// Gets the model name which was used to bind the model.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
/// This property can be used during validation to add model state for a bound model.
|
/// This property can be used during validation to add model state for a bound model.
|
||||||
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Key { get; }
|
public string Key { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not the <see cref="Model"/> value has been set.
|
/// <para>
|
||||||
///
|
/// Gets a value indicating whether or not the <see cref="Model"/> value has been set.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
/// This property can be used to distinguish between a model binder which does not find a value and
|
/// This property can be used to distinguish between a model binder which does not find a value and
|
||||||
/// the case where a model binder sets the <c>null</c> value.
|
/// the case where a model binder sets the <c>null</c> value.
|
||||||
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsModelSet { get; }
|
public bool IsModelSet { get; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
||||||
if (bindingContext.ModelType == typeof(HttpRequestMessage))
|
if (bindingContext.ModelType == typeof(HttpRequestMessage))
|
||||||
{
|
{
|
||||||
var model = bindingContext.OperationBindingContext.HttpContext.GetHttpRequestMessage();
|
var model = bindingContext.OperationBindingContext.HttpContext.GetHttpRequestMessage();
|
||||||
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, true));
|
return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult<ModelBindingResult>(null);
|
return Task.FromResult<ModelBindingResult>(null);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
#if DNX451
|
#if DNX451
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -25,11 +24,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
var binder = new KeyValuePairModelBinder<int, string>();
|
var binder = new KeyValuePairModelBinder<int, string>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var retVal = await binder.BindModelAsync(bindingContext);
|
var result = await binder.BindModelAsync(bindingContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(retVal);
|
Assert.NotNull(result);
|
||||||
Assert.Null(retVal.Model);
|
Assert.Null(result.Model);
|
||||||
Assert.False(bindingContext.ModelState.IsValid);
|
Assert.False(bindingContext.ModelState.IsValid);
|
||||||
Assert.Equal("someName", bindingContext.ModelName);
|
Assert.Equal("someName", bindingContext.ModelName);
|
||||||
var error = Assert.Single(bindingContext.ModelState["someName.Key"].Errors);
|
var error = Assert.Single(bindingContext.ModelState["someName.Key"].Errors);
|
||||||
|
|
@ -47,11 +46,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
var binder = new KeyValuePairModelBinder<int, string>();
|
var binder = new KeyValuePairModelBinder<int, string>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var retVal = await binder.BindModelAsync(bindingContext);
|
var result = await binder.BindModelAsync(bindingContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(retVal);
|
Assert.NotNull(result);
|
||||||
Assert.Null(retVal.Model);
|
Assert.Null(result.Model);
|
||||||
Assert.False(bindingContext.ModelState.IsValid);
|
Assert.False(bindingContext.ModelState.IsValid);
|
||||||
Assert.Equal("someName", bindingContext.ModelName);
|
Assert.Equal("someName", bindingContext.ModelName);
|
||||||
Assert.Equal(bindingContext.ModelState["someName.Value"].Errors.First().ErrorMessage, "A value is required.");
|
Assert.Equal(bindingContext.ModelState["someName.Value"].Errors.First().ErrorMessage, "A value is required.");
|
||||||
|
|
@ -73,10 +72,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
var binder = new KeyValuePairModelBinder<int, string>();
|
var binder = new KeyValuePairModelBinder<int, string>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var retVal = await binder.BindModelAsync(bindingContext);
|
var result = await binder.BindModelAsync(bindingContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(retVal);
|
Assert.Null(result);
|
||||||
Assert.True(bindingContext.ModelState.IsValid);
|
Assert.True(bindingContext.ModelState.IsValid);
|
||||||
Assert.Equal(0, bindingContext.ModelState.ErrorCount);
|
Assert.Equal(0, bindingContext.ModelState.ErrorCount);
|
||||||
}
|
}
|
||||||
|
|
@ -92,11 +91,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
var binder = new KeyValuePairModelBinder<int, string>();
|
var binder = new KeyValuePairModelBinder<int, string>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var retVal = await binder.BindModelAsync(bindingContext);
|
var result = await binder.BindModelAsync(bindingContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(retVal);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(new KeyValuePair<int, string>(42, "some-value"), retVal.Model);
|
Assert.Equal(new KeyValuePair<int, string>(42, "some-value"), result.Model);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -107,11 +106,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
var binder = new KeyValuePairModelBinder<int, string>();
|
var binder = new KeyValuePairModelBinder<int, string>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var retVal = await binder.TryBindStrongModel<int>(bindingContext, "key");
|
var result = await binder.TryBindStrongModel<int>(bindingContext, "key");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(retVal.IsModelSet);
|
Assert.True(result.IsModelSet);
|
||||||
Assert.Equal(42, retVal.Model);
|
Assert.Equal(42, result.Model);
|
||||||
Assert.Empty(bindingContext.ModelState);
|
Assert.Empty(bindingContext.ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,11 +132,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||||
var binder = new KeyValuePairModelBinder<int, string>();
|
var binder = new KeyValuePairModelBinder<int, string>();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var retVal = await binder.TryBindStrongModel<int>(bindingContext, "key");
|
var result = await binder.TryBindStrongModel<int>(bindingContext, "key");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(retVal.IsModelSet);
|
Assert.True(result.IsModelSet);
|
||||||
Assert.Null(retVal.Model);
|
Assert.Null(result.Model);
|
||||||
Assert.Empty(bindingContext.ModelState);
|
Assert.Empty(bindingContext.ModelState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http.Core;
|
using Microsoft.AspNet.Http.Core;
|
||||||
using Microsoft.AspNet.Testing;
|
using Microsoft.AspNet.Testing;
|
||||||
|
|
@ -106,17 +105,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanCreateModel_ReturnsFalse_ForNonTopLevelModel_IfModelIsMarkedWithBinderMetadata()
|
public async Task CanCreateModel_ReturnsFalse_ForNonTopLevelModel_IfModelIsMarkedWithBinderMetadata()
|
||||||
{
|
{
|
||||||
|
// Get the property metadata so that it is not a top level object.
|
||||||
var modelMetadata = GetMetadataForType(typeof(Document))
|
var modelMetadata = GetMetadataForType(typeof(Document))
|
||||||
.Properties
|
.Properties
|
||||||
.First(metadata => metadata.PropertyName == nameof(Document.SubDocument));
|
.First(metadata => metadata.PropertyName == nameof(Document.SubDocument));
|
||||||
var bindingContext = new MutableObjectBinderContext
|
var bindingContext = new MutableObjectBinderContext
|
||||||
{
|
{
|
||||||
ModelBindingContext = new ModelBindingContext
|
ModelBindingContext = new ModelBindingContext
|
||||||
{
|
{
|
||||||
// Get the property metadata so that it is not a top level object.
|
ModelMetadata = modelMetadata,
|
||||||
ModelMetadata = GetMetadataForType(typeof(Document))
|
|
||||||
.Properties
|
|
||||||
.First(metadata => metadata.PropertyName == nameof(Document.SubDocument)),
|
|
||||||
OperationBindingContext = new OperationBindingContext
|
OperationBindingContext = new OperationBindingContext
|
||||||
{
|
{
|
||||||
ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
|
ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
|
||||||
|
|
@ -381,7 +378,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
testableBinder
|
testableBinder
|
||||||
.Setup(o => o.GetMetadataForProperties(bindingContext))
|
.Setup(o => o.GetMetadataForProperties(bindingContext))
|
||||||
.Returns(new ModelMetadata[0]);
|
.Returns(new ModelMetadata[0]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var retValue = await testableBinder.Object.BindModelAsync(bindingContext);
|
var retValue = await testableBinder.Object.BindModelAsync(bindingContext);
|
||||||
|
|
@ -389,8 +386,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(retValue);
|
Assert.NotNull(retValue);
|
||||||
Assert.True(retValue.IsModelSet);
|
Assert.True(retValue.IsModelSet);
|
||||||
Assert.Same(model, retValue.Model);
|
var returnedPerson = Assert.IsType<Person>(retValue.Model);
|
||||||
Assert.IsType<Person>(retValue.Model);
|
Assert.Same(model, returnedPerson);
|
||||||
testableBinder.Verify();
|
testableBinder.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,8 +439,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(retValue);
|
Assert.NotNull(retValue);
|
||||||
Assert.True(retValue.IsModelSet);
|
Assert.True(retValue.IsModelSet);
|
||||||
Assert.Same(model, retValue.Model);
|
var returnedPerson = Assert.IsType<Person>(retValue.Model);
|
||||||
Assert.IsType<Person>(retValue.Model);
|
Assert.Same(model, returnedPerson);
|
||||||
testableBinder.Verify();
|
testableBinder.Verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue