Removing ModelMetadataProvider.GetModelMetadataForParameters
This commit is contained in:
parent
d166517dd6
commit
ac908d405e
17
Mvc.sln
17
Mvc.sln
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.22609.0
|
||||
VisualStudioVersion = 14.0.22711.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||
EndProject
|
||||
|
|
@ -154,6 +154,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestCo
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CorsWebSite", "test\WebSites\CorsWebSite\CorsWebSite.xproj", "{94BA134D-04B3-48AA-BA55-5A4DB8640F2D}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CorsMiddlewareWebSite", "test\WebSites\CorsMiddlewareWebSite\CorsMiddlewareWebSite.xproj", "{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -908,6 +910,18 @@ Global
|
|||
{94BA134D-04B3-48AA-BA55-5A4DB8640F2D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{94BA134D-04B3-48AA-BA55-5A4DB8640F2D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{94BA134D-04B3-48AA-BA55-5A4DB8640F2D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -983,5 +997,6 @@ Global
|
|||
{8AEB631E-AB74-4D2E-83FB-8931EE10D9D3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{F504357E-C2E1-4818-BA5C-9A2EAC25FEE5} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{94BA134D-04B3-48AA-BA55-5A4DB8640F2D} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{B42D4844-FFF8-4EC2-88D1-3AE95234D9EB} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Cors;
|
|||
using Microsoft.AspNet.Cors.Core;
|
||||
using Microsoft.AspNet.Mvc.Description;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
|
@ -343,7 +344,8 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
var attributes = parameterInfo.GetCustomAttributes(inherit: true).OfType<object>().ToArray();
|
||||
var parameterModel = new ParameterModel(parameterInfo, attributes);
|
||||
|
||||
parameterModel.BinderMetadata = attributes.OfType<IBinderMetadata>().FirstOrDefault();
|
||||
var bindingInfo = BindingInfo.GetBindingInfo(attributes);
|
||||
parameterModel.BindingInfo = bindingInfo;
|
||||
|
||||
parameterModel.ParameterName = parameterInfo.Name;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||
|
|
@ -24,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
{
|
||||
Action = other.Action;
|
||||
Attributes = new List<object>(other.Attributes);
|
||||
BinderMetadata = other.BinderMetadata;
|
||||
BindingInfo = other.BindingInfo;
|
||||
ParameterInfo = other.ParameterInfo;
|
||||
ParameterName = other.ParameterName;
|
||||
}
|
||||
|
|
@ -33,10 +35,10 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
|
||||
public IReadOnlyList<object> Attributes { get; }
|
||||
|
||||
public IBinderMetadata BinderMetadata { get; set; }
|
||||
|
||||
public ParameterInfo ParameterInfo { get; private set; }
|
||||
|
||||
public string ParameterName { get; set; }
|
||||
|
||||
public BindingInfo BindingInfo { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -276,9 +276,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
var parameterDescriptor = new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = parameter.BinderMetadata,
|
||||
Name = parameter.ParameterName,
|
||||
ParameterType = parameter.ParameterInfo.ParameterType,
|
||||
BindingInfo = parameter.BindingInfo
|
||||
};
|
||||
|
||||
return parameterDescriptor;
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
@ -44,29 +46,20 @@ namespace Microsoft.AspNet.Mvc
|
|||
nameof(actionContext));
|
||||
}
|
||||
|
||||
|
||||
var methodParameters = actionDescriptor.MethodInfo.GetParameters();
|
||||
var parameterMetadata = new List<ModelMetadata>();
|
||||
foreach (var parameter in actionDescriptor.Parameters)
|
||||
{
|
||||
var parameterInfo = methodParameters.Where(p => p.Name == parameter.Name).Single();
|
||||
var metadata = _modelMetadataProvider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: new object[] { parameter.BinderMetadata });
|
||||
|
||||
parameterMetadata.Add(metadata);
|
||||
}
|
||||
|
||||
var actionArguments = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||
await PopulateArgumentAsync(actionContext, actionBindingContext, actionArguments, parameterMetadata);
|
||||
await PopulateArgumentsAsync(
|
||||
actionContext,
|
||||
actionBindingContext,
|
||||
actionArguments,
|
||||
actionDescriptor.Parameters);
|
||||
return actionArguments;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PopulateArgumentAsync(
|
||||
private async Task PopulateArgumentsAsync(
|
||||
ActionContext actionContext,
|
||||
ActionBindingContext bindingContext,
|
||||
IDictionary<string, object> arguments,
|
||||
IEnumerable<ModelMetadata> parameterMetadata)
|
||||
IEnumerable<ParameterDescriptor> parameterMetadata)
|
||||
{
|
||||
var operationBindingContext = new OperationBindingContext
|
||||
{
|
||||
|
|
@ -81,15 +74,24 @@ namespace Microsoft.AspNet.Mvc
|
|||
modelState.MaxAllowedErrors = _options.MaxModelValidationErrors;
|
||||
foreach (var parameter in parameterMetadata)
|
||||
{
|
||||
var parameterType = parameter.ModelType;
|
||||
var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
|
||||
var parameterType = parameter.ParameterType;
|
||||
var modelBindingContext = GetModelBindingContext(
|
||||
parameter.Name,
|
||||
metadata,
|
||||
parameter.BindingInfo,
|
||||
modelState,
|
||||
operationBindingContext);
|
||||
|
||||
var modelBindingContext = GetModelBindingContext(parameter, modelState, operationBindingContext);
|
||||
var modelBindingResult = await bindingContext.ModelBinder.BindModelAsync(modelBindingContext);
|
||||
if (modelBindingResult != null && modelBindingResult.IsModelSet)
|
||||
{
|
||||
var modelExplorer = new ModelExplorer(_modelMetadataProvider, parameter, modelBindingResult.Model);
|
||||
var modelExplorer = new ModelExplorer(
|
||||
_modelMetadataProvider,
|
||||
metadata,
|
||||
modelBindingResult.Model);
|
||||
|
||||
arguments[parameter.PropertyName] = modelBindingResult.Model;
|
||||
arguments[parameter.Name] = modelBindingResult.Model;
|
||||
var validationContext = new ModelValidationContext(
|
||||
modelBindingResult.Key,
|
||||
bindingContext.ValidatorProvider,
|
||||
|
|
@ -100,23 +102,21 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
// Internal for tests
|
||||
internal static ModelBindingContext GetModelBindingContext(
|
||||
ModelMetadata modelMetadata,
|
||||
private static ModelBindingContext GetModelBindingContext(
|
||||
string parameterName,
|
||||
ModelMetadata metadata,
|
||||
BindingInfo bindingInfo,
|
||||
ModelStateDictionary modelState,
|
||||
OperationBindingContext operationBindingContext)
|
||||
{
|
||||
var modelBindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelName = modelMetadata.BinderModelName ?? modelMetadata.PropertyName,
|
||||
ModelMetadata = modelMetadata,
|
||||
ModelState = modelState,
|
||||
var modelBindingContext = ModelBindingContext.GetModelBindingContext(
|
||||
metadata,
|
||||
bindingInfo,
|
||||
parameterName);
|
||||
|
||||
// Fallback only if there is no explicit model name set.
|
||||
FallbackToEmptyPrefix = modelMetadata.BinderModelName == null,
|
||||
ValueProvider = operationBindingContext.ValueProvider,
|
||||
OperationBindingContext = operationBindingContext,
|
||||
};
|
||||
modelBindingContext.ModelState = modelState;
|
||||
modelBindingContext.ValueProvider = operationBindingContext.ValueProvider;
|
||||
modelBindingContext.OperationBindingContext = operationBindingContext;
|
||||
|
||||
return modelBindingContext;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Routing.Template;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
|
@ -127,7 +129,6 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
|
||||
return apiDescription;
|
||||
}
|
||||
|
||||
private IList<ApiParameterDescription> GetParameters(ApiParameterContext context)
|
||||
{
|
||||
// First, get parameters from the model-binding/parameter-binding side of the world.
|
||||
|
|
@ -136,7 +137,13 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
foreach (var actionParameter in context.ActionDescriptor.Parameters)
|
||||
{
|
||||
var visitor = new PseudoModelBindingVisitor(context, actionParameter);
|
||||
visitor.WalkParameter();
|
||||
var metadata = _modelMetadataProvider.GetMetadataForType(actionParameter.ParameterType);
|
||||
|
||||
var bindingContext = ApiParameterDescriptionContext.GetContext(
|
||||
metadata,
|
||||
actionParameter.BindingInfo,
|
||||
propertyName: actionParameter.Name);
|
||||
visitor.WalkParameter(bindingContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -422,6 +429,32 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
public IReadOnlyList<TemplatePart> RouteParameters { get; }
|
||||
}
|
||||
|
||||
private class ApiParameterDescriptionContext
|
||||
{
|
||||
public ModelMetadata ModelMetadata { get; set; }
|
||||
|
||||
public string BinderModelName { get; set; }
|
||||
|
||||
public BindingSource BindingSource { get; set; }
|
||||
|
||||
public string PropertyName { get; set; }
|
||||
|
||||
public static ApiParameterDescriptionContext GetContext(
|
||||
ModelMetadata metadata,
|
||||
BindingInfo bindingInfo,
|
||||
string propertyName)
|
||||
{
|
||||
// BindingMetadata can be null if the metadata represents properties.
|
||||
return new ApiParameterDescriptionContext
|
||||
{
|
||||
ModelMetadata = metadata,
|
||||
BinderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName,
|
||||
BindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource,
|
||||
PropertyName = propertyName ?? metadata.PropertyName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class PseudoModelBindingVisitor
|
||||
{
|
||||
public PseudoModelBindingVisitor(ApiParameterContext context, ParameterDescriptor parameter)
|
||||
|
|
@ -439,29 +472,20 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
// Avoid infinite recursion by tracking properties.
|
||||
private HashSet<PropertyKey> Visited { get; }
|
||||
|
||||
public void WalkParameter()
|
||||
public void WalkParameter(ApiParameterDescriptionContext context)
|
||||
{
|
||||
var parameterInfo =
|
||||
Context.ActionDescriptor.MethodInfo.GetParameters()
|
||||
.Where(p => p.Name == Parameter.Name)
|
||||
.Single();
|
||||
|
||||
var modelMetadata = Context.MetadataProvider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: new object[] { Parameter.BinderMetadata });
|
||||
|
||||
// Attempt to find a binding source for the parameter
|
||||
//
|
||||
// The default is ModelBinding (aka all default value providers)
|
||||
var source = BindingSource.ModelBinding;
|
||||
if (!Visit(modelMetadata, source, containerName: string.Empty))
|
||||
if (!Visit(context, source, containerName: string.Empty))
|
||||
{
|
||||
// If we get here, then it means we didn't find a match for any of the model. This means that it's
|
||||
// likely 'model-bound' in the traditional MVC sense (formdata + query string + route data) and
|
||||
// doesn't use any IBinderMetadata.
|
||||
//
|
||||
// Add a single 'default' parameter description for the model.
|
||||
Context.Results.Add(CreateResult(modelMetadata, source, containerName: string.Empty));
|
||||
Context.Results.Add(CreateResult(context, source, containerName: string.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -481,18 +505,23 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
/// or NONE of it. If a parameter description is created for ANY sub-properties of the model, then a parameter
|
||||
/// description will be created for ALL of them.
|
||||
/// </remarks>
|
||||
private bool Visit(ModelMetadata modelMetadata, BindingSource ambientSource, string containerName)
|
||||
private bool Visit(
|
||||
ApiParameterDescriptionContext bindingContext,
|
||||
BindingSource ambientSource,
|
||||
string containerName)
|
||||
{
|
||||
var source = modelMetadata.BindingSource;
|
||||
var source = bindingContext.BindingSource;
|
||||
if (source != null && source.IsGreedy)
|
||||
{
|
||||
// We have a definite answer for this model. This is a greedy source like
|
||||
// [FromBody] so there's no need to consider properties.
|
||||
Context.Results.Add(CreateResult(modelMetadata, source, containerName));
|
||||
Context.Results.Add(CreateResult(bindingContext, source, containerName));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var modelMetadata = bindingContext.ModelMetadata;
|
||||
|
||||
// For any property which is a leaf node, we don't want to keep traversing:
|
||||
//
|
||||
// 1) Collections - while it's possible to have binder attributes on the inside of a collection,
|
||||
|
|
@ -517,7 +546,7 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
{
|
||||
// We found a new source, and this model has no properties. This is probabaly
|
||||
// a simple type with an attribute like [FromQuery].
|
||||
Context.Results.Add(CreateResult(modelMetadata, source, containerName));
|
||||
Context.Results.Add(CreateResult(bindingContext, source, containerName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -545,29 +574,33 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
// Order - source: Body
|
||||
//
|
||||
|
||||
var unboundProperties = new HashSet<ModelMetadata>();
|
||||
var unboundProperties = new HashSet<ApiParameterDescriptionContext>();
|
||||
|
||||
// We don't want to append the **parameter** name when building a model name.
|
||||
var newContainerName = containerName;
|
||||
if (modelMetadata.ContainerType != null)
|
||||
{
|
||||
newContainerName = GetName(containerName, modelMetadata);
|
||||
newContainerName = GetName(containerName, bindingContext);
|
||||
}
|
||||
|
||||
foreach (var propertyMetadata in modelMetadata.Properties)
|
||||
{
|
||||
var key = new PropertyKey(propertyMetadata, source);
|
||||
|
||||
var propertyContext = ApiParameterDescriptionContext.GetContext(
|
||||
propertyMetadata,
|
||||
bindingInfo: null,
|
||||
propertyName: null);
|
||||
if (Visited.Add(key))
|
||||
{
|
||||
if (!Visit(propertyMetadata, source ?? ambientSource, newContainerName))
|
||||
if (!Visit(propertyContext, source ?? ambientSource, newContainerName))
|
||||
{
|
||||
unboundProperties.Add(propertyMetadata);
|
||||
unboundProperties.Add(propertyContext);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unboundProperties.Add(propertyMetadata);
|
||||
unboundProperties.Add(propertyContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -582,7 +615,7 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
{
|
||||
// We found a new source, and didn't create a result for any of the properties yet,
|
||||
// so create a result for the current object.
|
||||
Context.Results.Add(CreateResult(modelMetadata, source, containerName));
|
||||
Context.Results.Add(CreateResult(bindingContext, source, containerName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -600,20 +633,20 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
}
|
||||
|
||||
private ApiParameterDescription CreateResult(
|
||||
ModelMetadata metadata,
|
||||
ApiParameterDescriptionContext bindingContext,
|
||||
BindingSource source,
|
||||
string containerName)
|
||||
{
|
||||
return new ApiParameterDescription()
|
||||
{
|
||||
ModelMetadata = metadata,
|
||||
Name = GetName(containerName, metadata),
|
||||
ModelMetadata = bindingContext.ModelMetadata,
|
||||
Name = GetName(containerName, bindingContext),
|
||||
Source = source,
|
||||
Type = metadata.ModelType,
|
||||
Type = bindingContext.ModelMetadata.ModelType,
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetName(string containerName, ModelMetadata metadata)
|
||||
private static string GetName(string containerName, ApiParameterDescriptionContext metadata)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(metadata.BinderModelName))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
{
|
||||
ParameterName = inner.Name;
|
||||
ParameterType = inner.ParameterType;
|
||||
BinderMetadataType = inner.BinderMetadata?.GetType();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -30,11 +29,6 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
/// </summary>
|
||||
public Type ParameterType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Type"/> of the <see cref="ParameterDescriptor.BinderMetadata"/>.
|
||||
/// </summary>
|
||||
public Type BinderMetadataType { get; }
|
||||
|
||||
public override string Format()
|
||||
{
|
||||
return LogFormatter.FormatLogValues(this);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
{
|
||||
ParameterName = inner.ParameterName;
|
||||
ParameterType = inner.ParameterInfo.ParameterType;
|
||||
BinderMetadata = inner.BinderMetadata?.GetType();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -32,11 +31,6 @@ namespace Microsoft.AspNet.Mvc.Logging
|
|||
/// </summary>
|
||||
public Type ParameterType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Type"/> of the <see cref="ParameterModel.BinderMetadata"/>.
|
||||
/// </summary>
|
||||
public Type BinderMetadata { get; }
|
||||
|
||||
public override string Format()
|
||||
{
|
||||
return LogFormatter.FormatLogValues(this);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
|
|
@ -12,6 +13,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
public Type ParameterType { get; set; }
|
||||
|
||||
public IBinderMetadata BinderMetadata { get; set; }
|
||||
public BindingInfo BindingInfo { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +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.
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for metadata related to model binders.
|
||||
/// </summary>
|
||||
public interface IBinderMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// <summary>
|
||||
/// Metadata which specificies the data source for model binding.
|
||||
/// </summary>
|
||||
public interface IBindingSourceMetadata : IBinderMetadata
|
||||
public interface IBindingSourceMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="BindingSource"/>.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
|
||||
{
|
||||
if (bindingContext.ModelMetadata.BinderType == null)
|
||||
if (bindingContext.BinderType == null)
|
||||
{
|
||||
// Return null so that we are able to continue with the default set of model binders,
|
||||
// if there is no specific model binder provided.
|
||||
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
|
||||
var createFactory = _typeActivatorCache.GetOrAdd(bindingContext.ModelMetadata.BinderType, _createFactory);
|
||||
var createFactory = _typeActivatorCache.GetOrAdd(bindingContext.BinderType, _createFactory);
|
||||
var instance = createFactory(requestServices, arguments: null);
|
||||
|
||||
var modelBinder = instance as IModelBinder;
|
||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatBinderType_MustBeIModelBinderOrIModelBinderProvider(
|
||||
bindingContext.ModelMetadata.BinderType.FullName,
|
||||
bindingContext.BinderType.FullName,
|
||||
typeof(IModelBinder).FullName,
|
||||
typeof(IModelBinderProvider).FullName));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// <inheritdoc />
|
||||
public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext context)
|
||||
{
|
||||
var allowedBindingSource = context.ModelMetadata.BindingSource;
|
||||
var allowedBindingSource = context.BindingSource;
|
||||
if (allowedBindingSource == null || !allowedBindingSource.CanAcceptDataFrom(BindingSource))
|
||||
{
|
||||
// Binding Sources are opt-in. This model either didn't specify one or specified something
|
||||
|
|
|
|||
|
|
@ -50,16 +50,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var rawValueArray = RawValueToObjectArray(rawValue);
|
||||
foreach (var rawValueElement in rawValueArray)
|
||||
{
|
||||
var innerBindingContext = new ModelBindingContext(bindingContext,
|
||||
bindingContext.ModelName,
|
||||
elementMetadata)
|
||||
var innerBindingContext = ModelBindingContext.GetChildModelBindingContext(
|
||||
bindingContext,
|
||||
bindingContext.ModelName,
|
||||
elementMetadata);
|
||||
innerBindingContext.ValueProvider = new CompositeValueProvider
|
||||
{
|
||||
ValueProvider = new CompositeValueProvider
|
||||
{
|
||||
// our temporary provider goes at the front of the list
|
||||
new ElementalValueProvider(bindingContext.ModelName, rawValueElement, culture),
|
||||
bindingContext.ValueProvider
|
||||
}
|
||||
// our temporary provider goes at the front of the list
|
||||
new ElementalValueProvider(bindingContext.ModelName, rawValueElement, culture),
|
||||
bindingContext.ValueProvider
|
||||
};
|
||||
|
||||
object boundValue = null;
|
||||
|
|
@ -105,7 +104,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
foreach (var indexName in indexNames)
|
||||
{
|
||||
var fullChildName = ModelBindingHelper.CreateIndexModelName(bindingContext.ModelName, indexName);
|
||||
var childBindingContext = new ModelBindingContext(bindingContext, fullChildName, elementMetadata);
|
||||
var childBindingContext = ModelBindingContext.GetChildModelBindingContext(
|
||||
bindingContext,
|
||||
fullChildName,
|
||||
elementMetadata);
|
||||
|
||||
var didBind = false;
|
||||
object boundValue = null;
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var dto = (ComplexModelDto)bindingContext.Model;
|
||||
foreach (var propertyMetadata in dto.PropertyMetadata)
|
||||
{
|
||||
var propertyModelName = ModelBindingHelper.CreatePropertyModelName(
|
||||
bindingContext.ModelName,
|
||||
propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName);
|
||||
var propertyModelName = ModelBindingHelper.CreatePropertyModelName(
|
||||
bindingContext.ModelName,
|
||||
propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName);
|
||||
|
||||
var propertyBindingContext = new ModelBindingContext(bindingContext,
|
||||
propertyModelName,
|
||||
propertyMetadata);
|
||||
var propertyBindingContext = ModelBindingContext.GetChildModelBindingContext(
|
||||
bindingContext,
|
||||
propertyModelName,
|
||||
propertyMetadata);
|
||||
|
||||
// bind and propagate the values
|
||||
// If we can't bind then leave the result missing (don't add a null).
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
ValueProvider = oldBindingContext.ValueProvider,
|
||||
OperationBindingContext = oldBindingContext.OperationBindingContext,
|
||||
PropertyFilter = oldBindingContext.PropertyFilter,
|
||||
BinderModelName = oldBindingContext.BinderModelName,
|
||||
BindingSource = oldBindingContext.BindingSource,
|
||||
BinderType = oldBindingContext.BinderType,
|
||||
};
|
||||
|
||||
newBindingContext.OperationBindingContext.BodyBindingState = GetBodyBindingState(oldBindingContext);
|
||||
|
|
@ -139,7 +142,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// public IActionResult UpdatePerson([FromForm] Person person) { }
|
||||
//
|
||||
// In this example, [FromQuery] overrides the ambient data source (form).
|
||||
var bindingSource = oldBindingContext.ModelMetadata.BindingSource;
|
||||
var bindingSource = oldBindingContext.BindingSource;
|
||||
if (bindingSource != null && !bindingSource.IsGreedy)
|
||||
{
|
||||
var valueProvider =
|
||||
|
|
@ -155,7 +158,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
private static BodyBindingState GetBodyBindingState(ModelBindingContext oldBindingContext)
|
||||
{
|
||||
var bindingSource = oldBindingContext.ModelMetadata.BindingSource;
|
||||
var bindingSource = oldBindingContext.BindingSource;
|
||||
|
||||
var willReadBodyWithFormatter = bindingSource == BindingSource.Body;
|
||||
var willReadBodyAsFormData = bindingSource == BindingSource.Form;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var modelMetadata = bindingContext.ModelMetadata;
|
||||
|
||||
// Property name can be null if the model metadata represents a type (rather than a property or parameter).
|
||||
var headerName = modelMetadata.BinderModelName ?? modelMetadata.PropertyName ?? bindingContext.ModelName;
|
||||
var headerName = bindingContext.BinderModelName ?? modelMetadata.PropertyName ?? bindingContext.ModelName;
|
||||
object model = null;
|
||||
if (bindingContext.ModelType == typeof(string))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,8 +54,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
parentBindingContext.OperationBindingContext.MetadataProvider.GetMetadataForType(typeof(TModel));
|
||||
var propertyModelName =
|
||||
ModelBindingHelper.CreatePropertyModelName(parentBindingContext.ModelName, propertyName);
|
||||
var propertyBindingContext =
|
||||
new ModelBindingContext(parentBindingContext, propertyModelName, propertyModelMetadata);
|
||||
var propertyBindingContext = ModelBindingContext.GetChildModelBindingContext(
|
||||
parentBindingContext,
|
||||
propertyModelName,
|
||||
propertyModelMetadata);
|
||||
|
||||
propertyBindingContext.BinderModelName = propertyModelMetadata.BinderModelName;
|
||||
|
||||
var modelBindingResult =
|
||||
await propertyBindingContext.OperationBindingContext.ModelBinder.BindModelAsync(propertyBindingContext);
|
||||
if (modelBindingResult != null)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
|
|
@ -53,7 +54,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
var bindingContext = context.ModelBindingContext;
|
||||
var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;
|
||||
var hasExplicitAlias = bindingContext.ModelMetadata.BinderModelName != null;
|
||||
var hasExplicitAlias = bindingContext.BinderModelName != null;
|
||||
|
||||
// If we get here the model is a complex object which was not directly bound by any previous model binder,
|
||||
// so we want to decide if we want to continue binding. This is important to get right to avoid infinite
|
||||
|
|
@ -67,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
//
|
||||
// We skip this check if it is a top level object because we want to always evaluate
|
||||
// the creation of top level object (this is also required for ModelBinderAttribute to work.)
|
||||
var bindingSource = bindingContext.ModelMetadata.BindingSource;
|
||||
var bindingSource = bindingContext.BindingSource;
|
||||
if (!isTopLevelObject &&
|
||||
bindingSource != null &&
|
||||
bindingSource.IsGreedy)
|
||||
|
|
@ -144,8 +145,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
isAnyPropertyEnabledForValueProviderBasedBinding = true;
|
||||
|
||||
var propertyModelName = ModelBindingHelper.CreatePropertyModelName(
|
||||
context.ModelBindingContext.ModelName,
|
||||
propertyMetadata.BinderModelName ?? propertyMetadata.PropertyName);
|
||||
|
||||
var propertyModelBindingContext = ModelBindingContext.GetChildModelBindingContext(
|
||||
context.ModelBindingContext,
|
||||
propertyModelName,
|
||||
propertyMetadata);
|
||||
|
||||
// If any property can return a true value.
|
||||
if (await CanBindValue(context.ModelBindingContext, propertyMetadata))
|
||||
if (await CanBindValue(propertyModelBindingContext))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -164,11 +174,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> CanBindValue(ModelBindingContext bindingContext, ModelMetadata metadata)
|
||||
private async Task<bool> CanBindValue(ModelBindingContext bindingContext)
|
||||
{
|
||||
var valueProvider = bindingContext.ValueProvider;
|
||||
|
||||
var bindingSource = metadata.BindingSource;
|
||||
var bindingSource = bindingContext.BindingSource;
|
||||
if (bindingSource != null && !bindingSource.IsGreedy)
|
||||
{
|
||||
var rootValueProvider = bindingContext.OperationBindingContext.ValueProvider as IBindingSourceValueProvider;
|
||||
|
|
@ -178,11 +188,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
}
|
||||
|
||||
var propertyModelName = ModelBindingHelper.CreatePropertyModelName(
|
||||
bindingContext.ModelName,
|
||||
metadata.BinderModelName ?? metadata.PropertyName);
|
||||
|
||||
if (await valueProvider.ContainsPrefixAsync(propertyModelName))
|
||||
if (await valueProvider.ContainsPrefixAsync(bindingContext.ModelName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -248,13 +254,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
|
||||
var dtoMetadata = metadataProvider.GetMetadataForType(typeof(ComplexModelDto));
|
||||
|
||||
var childContext = new ModelBindingContext(
|
||||
var childContext = ModelBindingContext.GetChildModelBindingContext(
|
||||
bindingContext,
|
||||
bindingContext.ModelName,
|
||||
dtoMetadata)
|
||||
{
|
||||
Model = dto,
|
||||
};
|
||||
dtoMetadata);
|
||||
|
||||
childContext.Model = dto;
|
||||
|
||||
return await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(childContext);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Binding info which represents metadata associated to an action parameter.
|
||||
/// </summary>
|
||||
public class BindingInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ModelBinding.BindingSource"/>.
|
||||
/// </summary>
|
||||
public BindingSource BindingSource { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the binder model name.
|
||||
/// </summary>
|
||||
public string BinderModelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Type"/> of the model binder used to bind the model.
|
||||
/// </summary>
|
||||
public Type BinderType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ModelBinding.IPropertyBindingPredicateProvider"/>.
|
||||
/// </summary>
|
||||
public IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="BindingInfo"/> from the given <paramref name="attributes"/>.
|
||||
/// </summary>
|
||||
/// <param name="attributes">A collection of attributes which are used to construct <see cref="BindingInfo"/>
|
||||
/// </param>
|
||||
/// <returns>A new instance of <see cref="BindingInfo"/>.</returns>
|
||||
public static BindingInfo GetBindingInfo(IEnumerable<object> attributes)
|
||||
{
|
||||
var bindingInfo = new BindingInfo();
|
||||
|
||||
// BinderModelName
|
||||
foreach (var binderModelNameAttribute in attributes.OfType<IModelNameProvider>())
|
||||
{
|
||||
if (binderModelNameAttribute?.Name != null)
|
||||
{
|
||||
bindingInfo.BinderModelName = binderModelNameAttribute.Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// BinderType
|
||||
foreach (var binderTypeAttribute in attributes.OfType<IBinderTypeProviderMetadata>())
|
||||
{
|
||||
if (binderTypeAttribute.BinderType != null)
|
||||
{
|
||||
bindingInfo.BinderType = binderTypeAttribute.BinderType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// BindingSource
|
||||
foreach (var bindingSourceAttribute in attributes.OfType<IBindingSourceMetadata>())
|
||||
{
|
||||
if (bindingSourceAttribute.BindingSource != null)
|
||||
{
|
||||
bindingInfo.BindingSource = bindingSourceAttribute.BindingSource;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyBindingPredicateProvider
|
||||
var predicateProviders = attributes.OfType<IPropertyBindingPredicateProvider>().ToArray();
|
||||
if (predicateProviders.Length > 0)
|
||||
{
|
||||
bindingInfo.PropertyBindingPredicateProvider = new CompositePredicateProvider(
|
||||
predicateProviders);
|
||||
}
|
||||
|
||||
return bindingInfo;
|
||||
}
|
||||
|
||||
private class CompositePredicateProvider : IPropertyBindingPredicateProvider
|
||||
{
|
||||
private readonly IEnumerable<IPropertyBindingPredicateProvider> _providers;
|
||||
|
||||
public CompositePredicateProvider(IEnumerable<IPropertyBindingPredicateProvider> providers)
|
||||
{
|
||||
_providers = providers;
|
||||
}
|
||||
|
||||
public Func<ModelBindingContext, string, bool> PropertyFilter
|
||||
{
|
||||
get
|
||||
{
|
||||
return CreatePredicate();
|
||||
}
|
||||
}
|
||||
|
||||
private Func<ModelBindingContext, string, bool> CreatePredicate()
|
||||
{
|
||||
var predicates = _providers
|
||||
.Select(p => p.PropertyFilter)
|
||||
.Where(p => p != null);
|
||||
|
||||
return (context, propertyName) =>
|
||||
{
|
||||
foreach (var predicate in predicates)
|
||||
{
|
||||
if (!predicate(context, propertyName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
ModelMetadata GetMetadataForType([NotNull] Type modelType);
|
||||
|
||||
IEnumerable<ModelMetadata> GetMetadataForProperties([NotNull] Type modelType);
|
||||
|
||||
ModelMetadata GetMetadataForParameter([NotNull] ParameterInfo parameter, IEnumerable<object> attributes);
|
||||
}
|
||||
}
|
||||
|
|
@ -16,17 +16,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
/// <inheritdoc />
|
||||
public void GetBindingMetadata([NotNull] BindingMetadataProviderContext context)
|
||||
{
|
||||
// For Model Name - we only use the first attribute we find. An attribute on the parameter
|
||||
// is considered an override of an attribute on the type. This is for compatibility with [Bind]
|
||||
// from MVC 5.
|
||||
//
|
||||
// BinderType and BindingSource fall back to the first attribute to provide a value.
|
||||
|
||||
// BinderModelName
|
||||
var binderModelNameAttribute = context.Attributes.OfType<IModelNameProvider>().FirstOrDefault();
|
||||
if (binderModelNameAttribute?.Name != null)
|
||||
foreach (var binderModelNameAttribute in context.Attributes.OfType<IModelNameProvider>())
|
||||
{
|
||||
context.BindingMetadata.BinderModelName = binderModelNameAttribute.Name;
|
||||
if (binderModelNameAttribute?.Name != null)
|
||||
{
|
||||
context.BindingMetadata.BinderModelName = binderModelNameAttribute.Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// BinderType
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
public class DefaultModelMetadataProvider : IModelMetadataProvider
|
||||
{
|
||||
private readonly TypeCache _typeCache = new TypeCache();
|
||||
private readonly ParameterCache _parameterCache = new ParameterCache();
|
||||
private readonly PropertiesCache _propertiesCache = new PropertiesCache();
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -32,23 +31,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
/// </summary>
|
||||
protected ICompositeMetadataDetailsProvider DetailsProvider { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual ModelMetadata GetMetadataForParameter(
|
||||
[NotNull] ParameterInfo parameterInfo,
|
||||
[NotNull] IEnumerable<object> attributes)
|
||||
{
|
||||
var key = ModelMetadataIdentity.ForParameter(parameterInfo);
|
||||
|
||||
DefaultMetadataDetailsCache entry;
|
||||
if (!_parameterCache.TryGetValue(key, out entry))
|
||||
{
|
||||
entry = CreateParameterCacheEntry(key, attributes);
|
||||
entry = _parameterCache.GetOrAdd(key, entry);
|
||||
}
|
||||
|
||||
return CreateModelMetadata(entry);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual IEnumerable<ModelMetadata> GetMetadataForProperties([NotNull]Type modelType)
|
||||
{
|
||||
|
|
@ -152,37 +134,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
return new DefaultMetadataDetailsCache(key, attributes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="DefaultMetadataDetailsCache"/> entry for a parameter.
|
||||
/// </summary>
|
||||
/// <param name="key">
|
||||
/// The <see cref="ModelMetadataIdentity"/> identifying the model parameter.
|
||||
/// </param>
|
||||
/// <param name="attributes">
|
||||
/// The set of model attributes applied to the parameter.
|
||||
/// </param>
|
||||
/// <returns>A cache object for the model parameter.</returns>
|
||||
/// <remarks>
|
||||
/// The results of this method will be cached and used to satisfy calls to
|
||||
/// <see cref="GetMetadataForParameter(ParameterInfo, IEnumerable{object}))"/>.
|
||||
/// Override this method to provide a different set of attributes.
|
||||
/// </remarks>
|
||||
protected virtual DefaultMetadataDetailsCache CreateParameterCacheEntry(
|
||||
[NotNull] ModelMetadataIdentity key,
|
||||
[NotNull] IEnumerable<object> attributes)
|
||||
{
|
||||
var allAttributes = new List<object>();
|
||||
|
||||
if (attributes != null)
|
||||
{
|
||||
allAttributes.AddRange(attributes);
|
||||
}
|
||||
|
||||
allAttributes.AddRange(ModelAttributes.GetAttributesForParameter(key.ParameterInfo));
|
||||
|
||||
return new DefaultMetadataDetailsCache(key, allAttributes);
|
||||
}
|
||||
|
||||
private class TypeCache : ConcurrentDictionary<ModelMetadataIdentity, DefaultMetadataDetailsCache>
|
||||
{
|
||||
}
|
||||
|
|
@ -190,9 +141,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
private class PropertiesCache : ConcurrentDictionary<ModelMetadataIdentity, DefaultMetadataDetailsCache[]>
|
||||
{
|
||||
}
|
||||
|
||||
private class ParameterCache : ConcurrentDictionary<ModelMetadataIdentity, DefaultMetadataDetailsCache>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,22 +15,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// </summary>
|
||||
public static class ModelAttributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the attributes for the given <paramref name="parameter"/>.
|
||||
/// </summary>
|
||||
/// <param name="parameter">A <see cref="ParameterInfo"/> for which attributes need to be resolved.
|
||||
/// </param>
|
||||
/// <returns>An <see cref="IEnumerable{object}"/> containing the attributes on the
|
||||
/// <paramref name="parameter"/> before the attributes on the <paramref name="parameter"/> type.</returns>
|
||||
public static IEnumerable<object> GetAttributesForParameter(ParameterInfo parameter)
|
||||
{
|
||||
// Return the parameter attributes first.
|
||||
var parameterAttributes = parameter.GetCustomAttributes();
|
||||
var typeAttributes = parameter.ParameterType.GetTypeInfo().GetCustomAttributes();
|
||||
|
||||
return parameterAttributes.Concat(typeAttributes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attributes for the given <paramref name="property"/>.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -89,11 +89,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
{
|
||||
get
|
||||
{
|
||||
if (ParameterInfo != null)
|
||||
{
|
||||
return ModelMetadataKind.Parameter;
|
||||
}
|
||||
else if (ContainerType != null && Name != null)
|
||||
if (ContainerType != null && Name != null)
|
||||
{
|
||||
return ModelMetadataKind.Property;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
/// Used for <see cref="ModelMetadata"/> for a property.
|
||||
/// </summary>
|
||||
Property,
|
||||
|
||||
/// <summary>
|
||||
/// Used for <see cref="ModelMetadata"/> for a parameter.
|
||||
/// </summary>
|
||||
Parameter,
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
|
|
@ -28,26 +29,57 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ModelBindingContext"/> class using the
|
||||
/// Constructs a new instance of the <see cref="ModelBindingContext"/> class using the
|
||||
/// <paramref name="bindingContext" />.
|
||||
/// </summary>
|
||||
/// <param name="bindingContext">Existing <see cref="ModelBindingContext"/>.</param>
|
||||
/// <param name="modelName">Model name of associated with the new <see cref="ModelBindingContext"/>.</param>
|
||||
/// <param name="modelMetadata">Model metadata of associated with the new <see cref="ModelBindingContext"/>.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// This constructor copies certain values that won't change between parent and child objects,
|
||||
/// e.g. ValueProvider, ModelState
|
||||
/// </remarks>
|
||||
public ModelBindingContext([NotNull] ModelBindingContext bindingContext,
|
||||
[NotNull] string modelName,
|
||||
[NotNull] ModelMetadata modelMetadata)
|
||||
public static ModelBindingContext GetChildModelBindingContext(
|
||||
[NotNull] ModelBindingContext bindingContext,
|
||||
[NotNull] string modelName,
|
||||
[NotNull] ModelMetadata modelMetadata)
|
||||
{
|
||||
ModelName = modelName;
|
||||
ModelMetadata = modelMetadata;
|
||||
ModelState = bindingContext.ModelState;
|
||||
ValueProvider = bindingContext.ValueProvider;
|
||||
OperationBindingContext = bindingContext.OperationBindingContext;
|
||||
var modelBindingContext = new ModelBindingContext();
|
||||
modelBindingContext.ModelName = modelName;
|
||||
modelBindingContext.ModelMetadata = modelMetadata;
|
||||
modelBindingContext.ModelState = bindingContext.ModelState;
|
||||
modelBindingContext.ValueProvider = bindingContext.ValueProvider;
|
||||
modelBindingContext.OperationBindingContext = bindingContext.OperationBindingContext;
|
||||
|
||||
modelBindingContext.BindingSource = modelMetadata.BindingSource;
|
||||
modelBindingContext.BinderModelName = modelMetadata.BinderModelName;
|
||||
modelBindingContext.BinderType = modelMetadata.BinderType;
|
||||
return modelBindingContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new instance of <see cref="ModelBindingContext"/> from given <paramref name="metadata"/>
|
||||
/// and <paramref name="bindingInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="metadata"><see cref="ModelMetadata"/> associated with the model.</param>
|
||||
/// <param name="bindingInfo"><see cref="BindingInfo"/> associated with the model.</param>
|
||||
/// <param name="modelName">An optional name of the model to be used.</param>
|
||||
/// <returns>A new instance of <see cref="ModelBindingContext"/>.</returns>
|
||||
public static ModelBindingContext GetModelBindingContext(
|
||||
[NotNull] ModelMetadata metadata,
|
||||
[NotNull] BindingInfo bindingInfo,
|
||||
string modelName)
|
||||
{
|
||||
var binderModelName = bindingInfo.BinderModelName ?? metadata.BinderModelName;
|
||||
var propertyPredicateProvider =
|
||||
bindingInfo.PropertyBindingPredicateProvider ?? metadata.PropertyBindingPredicateProvider;
|
||||
return new ModelBindingContext()
|
||||
{
|
||||
ModelMetadata = metadata,
|
||||
BindingSource = bindingInfo.BindingSource ?? metadata.BindingSource,
|
||||
PropertyFilter = propertyPredicateProvider?.PropertyFilter,
|
||||
BinderType = bindingInfo.BinderType ?? metadata.BinderType,
|
||||
BinderModelName = binderModelName,
|
||||
ModelName = binderModelName ?? metadata.PropertyName ?? modelName,
|
||||
FallbackToEmptyPrefix = binderModelName == null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -118,6 +150,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a model name which is explicitly set using an <see cref="IModelNameProvider"/>.
|
||||
/// <see cref="Model"/>.
|
||||
/// </summary>
|
||||
public string BinderModelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value which represents the <see cref="BindingSource"/> associated with the
|
||||
/// <see cref="Model"/>.
|
||||
/// </summary>
|
||||
public BindingSource BindingSource { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Type"/> of an <see cref="IModelBinder"/> associated with the
|
||||
/// <see cref="Model"/>.
|
||||
/// </summary>
|
||||
public Type BinderType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that indicates whether the binder should use an empty prefix to look up
|
||||
/// values in <see cref="IValueProvider"/> when no values are found using the
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// 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.Linq;
|
||||
using System.Web.Http;
|
||||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
|
|
@ -15,30 +16,42 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
if (IsConventionApplicable(action.Controller))
|
||||
{
|
||||
var optionalParameters = new HashSet<string>();
|
||||
var uriBindingSource = (new FromUriAttribute()).BindingSource;
|
||||
foreach (var parameter in action.Parameters)
|
||||
{
|
||||
if (parameter.BinderMetadata is IBinderMetadata)
|
||||
// Some IBindingSourceMetadata attributes like ModelBinder attribute return null
|
||||
// as their binding source. Special case to ensure we do not ignore them.
|
||||
if (parameter.BindingInfo.BindingSource != null ||
|
||||
parameter.Attributes.OfType<IBindingSourceMetadata>().Any())
|
||||
{
|
||||
// This has a binding behavior configured, just leave it alone.
|
||||
}
|
||||
else if (ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType))
|
||||
{
|
||||
// Simple types are by-default from the URI.
|
||||
parameter.BinderMetadata = new FromUriAttribute();
|
||||
|
||||
parameter.BindingInfo.BindingSource = uriBindingSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Complex types are by-default from the body.
|
||||
parameter.BinderMetadata = new FromBodyAttribute();
|
||||
parameter.BindingInfo.BindingSource = BindingSource.Body;
|
||||
}
|
||||
|
||||
// If the parameter has a default value, we want to consider it as optional parameter by default.
|
||||
var optionalMetadata = parameter.BinderMetadata as FromUriAttribute;
|
||||
if (parameter.ParameterInfo.HasDefaultValue && optionalMetadata != null)
|
||||
// For all non IOptionalBinderMetadata, which are not URL source (like FromQuery etc.) do not
|
||||
// participate in overload selection and hence are added to the hashset so that they can be
|
||||
// ignored in OverloadActionConstraint.
|
||||
var optionalMetadata = parameter.Attributes.OfType<IOptionalBinderMetadata>().SingleOrDefault();
|
||||
if (parameter.ParameterInfo.HasDefaultValue && parameter.BindingInfo.BindingSource == uriBindingSource ||
|
||||
optionalMetadata != null && optionalMetadata.IsOptional ||
|
||||
optionalMetadata == null && parameter.BindingInfo.BindingSource != uriBindingSource)
|
||||
{
|
||||
optionalMetadata.IsOptional = true;
|
||||
optionalParameters.Add(parameter.ParameterName);
|
||||
}
|
||||
}
|
||||
|
||||
action.Properties.Add("OptionalParameters", optionalParameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,12 +87,13 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
}
|
||||
|
||||
var parameters = new List<OverloadedParameter>();
|
||||
|
||||
object optionalParametersObject;
|
||||
candidate.Action.Properties.TryGetValue("OptionalParameters", out optionalParametersObject);
|
||||
var optionalParameters = (HashSet<string>)optionalParametersObject;
|
||||
foreach (var parameter in candidate.Action.Parameters)
|
||||
{
|
||||
// We only consider parameters that are marked as bound from the URL.
|
||||
var bindingSourceMetadata = parameter?.BinderMetadata as IBindingSourceMetadata;
|
||||
var source = bindingSourceMetadata?.BindingSource;
|
||||
var source = parameter.BindingInfo.BindingSource;
|
||||
if (source == null)
|
||||
{
|
||||
continue;
|
||||
|
|
@ -102,17 +103,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
source.CanAcceptDataFrom(BindingSource.Query)) &&
|
||||
ValueProviderResult.CanConvertFromString(parameter.ParameterType))
|
||||
{
|
||||
var optionalMetadata = parameter.BinderMetadata as IOptionalBinderMetadata;
|
||||
if (optionalMetadata == null || optionalMetadata.IsOptional)
|
||||
if (optionalParameters != null)
|
||||
{
|
||||
// Optional parameters are ignored in overloading. If a parameter doesn't specify that it's
|
||||
// required then treat it as optional (MVC default). WebAPI parameters will all by-default
|
||||
// specify themselves as required unless they have a default value.
|
||||
continue;
|
||||
var isOptional = optionalParameters.Contains(parameter.Name);
|
||||
if (isOptional)
|
||||
{
|
||||
// Optional parameters are ignored in overloading. If a parameter doesn't specify that it's
|
||||
// required then treat it as optional (MVC default). WebAPI parameters will all by-default
|
||||
// specify themselves as required unless they have a default value.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var nameProvider = parameter.BinderMetadata as IModelNameProvider;
|
||||
var prefix = nameProvider?.Name ?? parameter.Name;
|
||||
var prefix = parameter.BindingInfo.BinderModelName ?? parameter.Name;
|
||||
|
||||
parameters.Add(new OverloadedParameter()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IBinderMetadata"/> that designates an optional parameter for the purposes
|
||||
/// An type that designates an optional parameter for the purposes
|
||||
/// of WebAPI action overloading. Optional parameters do not participate in overloading, and
|
||||
/// do not have to have a value for the action to be selected.
|
||||
///
|
||||
/// This has no impact when used without WebAPI action overloading.
|
||||
/// </summary>
|
||||
public interface IOptionalBinderMetadata : IBinderMetadata
|
||||
public interface IOptionalBinderMetadata
|
||||
{
|
||||
bool IsOptional { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ApplicationModels
|
||||
|
|
@ -18,7 +19,11 @@ namespace Microsoft.AspNet.Mvc.ApplicationModels
|
|||
new List<object>() { new FromBodyAttribute() });
|
||||
|
||||
parameter.Action = new ActionModel(typeof(TestController).GetMethod("Edit"), new List<object>());
|
||||
parameter.BinderMetadata = (IBinderMetadata)parameter.Attributes[0];
|
||||
parameter.BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = BindingSource.Body
|
||||
};
|
||||
|
||||
parameter.ParameterName = "id";
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Header);
|
||||
|
||||
var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider);
|
||||
bindingContext.BindingSource = BindingSource.Header;
|
||||
|
||||
var binder = bindingContext.OperationBindingContext.ModelBinder;
|
||||
|
||||
|
|
@ -113,6 +114,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
provider.ForType<Person>().BindingDetails(d => d.BindingSource = null);
|
||||
|
||||
var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider);
|
||||
bindingContext.BindingSource = null;
|
||||
|
||||
var binder = bindingContext.OperationBindingContext.ModelBinder;
|
||||
|
||||
|
|
@ -186,6 +188,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
ValueProvider = Mock.Of<IValueProvider>(),
|
||||
ModelState = new ModelStateDictionary(),
|
||||
OperationBindingContext = operationBindingContext,
|
||||
BindingSource = BindingSource.Body,
|
||||
};
|
||||
|
||||
return bindingContext;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Reflection;
|
|||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.Description;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Moq;
|
||||
|
|
@ -110,7 +111,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
var id = Assert.Single(main.Parameters);
|
||||
|
||||
Assert.Equal("id", id.Name);
|
||||
Assert.Null(id.BinderMetadata);
|
||||
Assert.Null(id.BindingInfo.BindingSource);
|
||||
Assert.Equal(typeof(int), id.ParameterType);
|
||||
}
|
||||
|
||||
|
|
@ -129,13 +130,13 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
var id = Assert.Single(main.Parameters, p => p.Name == "id");
|
||||
|
||||
Assert.Equal("id", id.Name);
|
||||
Assert.Null(id.BinderMetadata);
|
||||
Assert.Null(id.BindingInfo.BindingSource);
|
||||
Assert.Equal(typeof(int), id.ParameterType);
|
||||
|
||||
var entity = Assert.Single(main.Parameters, p => p.Name == "entity");
|
||||
|
||||
Assert.Equal("entity", entity.Name);
|
||||
Assert.IsType<FromBodyAttribute>(entity.BinderMetadata);
|
||||
Assert.Equal(entity.BindingInfo.BindingSource, BindingSource.Body);
|
||||
Assert.Equal(typeof(TestActionParameter), entity.ParameterType);
|
||||
}
|
||||
|
||||
|
|
@ -154,19 +155,19 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
var id = Assert.Single(main.Parameters, p => p.Name == "id");
|
||||
|
||||
Assert.Equal("id", id.Name);
|
||||
Assert.Null(id.BinderMetadata);
|
||||
Assert.Null(id.BindingInfo.BindingSource);
|
||||
Assert.Equal(typeof(int), id.ParameterType);
|
||||
|
||||
var upperCaseId = Assert.Single(main.Parameters, p => p.Name == "ID");
|
||||
|
||||
Assert.Equal("ID", upperCaseId.Name);
|
||||
Assert.Null(upperCaseId.BinderMetadata);
|
||||
Assert.Null(upperCaseId.BindingInfo.BindingSource);
|
||||
Assert.Equal(typeof(int), upperCaseId.ParameterType);
|
||||
|
||||
var pascalCaseId = Assert.Single(main.Parameters, p => p.Name == "Id");
|
||||
|
||||
Assert.Equal("Id", pascalCaseId.Name);
|
||||
Assert.Null(id.BinderMetadata);
|
||||
Assert.Null(id.BindingInfo.BindingSource);
|
||||
Assert.Equal(typeof(int), pascalCaseId.ParameterType);
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +188,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
var entity = Assert.Single(fromBody.Parameters);
|
||||
|
||||
Assert.Equal("entity", entity.Name);
|
||||
Assert.IsType<FromBodyAttribute>(entity.BinderMetadata);
|
||||
Assert.Equal(entity.BindingInfo.BindingSource, BindingSource.Body);
|
||||
Assert.Equal(typeof(TestActionParameter), entity.ParameterType);
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +209,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
var entity = Assert.Single(notFromBody.Parameters);
|
||||
|
||||
Assert.Equal("entity", entity.Name);
|
||||
Assert.Null(entity.BinderMetadata);
|
||||
Assert.Null(entity.BindingInfo.BindingSource);
|
||||
Assert.Equal(typeof(TestActionParameter), entity.ParameterType);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ using Microsoft.AspNet.Http;
|
|||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Testing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
|
@ -2073,6 +2074,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
Name = "value",
|
||||
ParameterType = typeof(int),
|
||||
BindingInfo = new BindingInfo(),
|
||||
}
|
||||
},
|
||||
FilterDescriptors = new List<FilterDescriptor>()
|
||||
|
|
@ -2106,11 +2108,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
metadataProvider,
|
||||
new DefaultObjectValidator(Mock.Of<IValidationExcludeFiltersProvider>(), metadataProvider),
|
||||
new MockMvcOptionsAccessor()),
|
||||
new MockModelBinderProvider() { ModelBinders = new List<IModelBinder>() { binder.Object } },
|
||||
new MockModelValidatorProviderProvider(),
|
||||
new MockValueProviderFactoryProvider(),
|
||||
new MockScopedInstance<ActionBindingContext>(),
|
||||
Mock.Of<ITempDataDictionary>());
|
||||
new MockModelBinderProvider() { ModelBinders = new List<IModelBinder>() { binder.Object } },
|
||||
new MockModelValidatorProviderProvider(),
|
||||
new MockValueProviderFactoryProvider(),
|
||||
new MockScopedInstance<ActionBindingContext>(),
|
||||
Mock.Of<ITempDataDictionary>());
|
||||
|
||||
// Act
|
||||
await invoker.InvokeAsync();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Routing.Constraints;
|
||||
|
|
@ -964,9 +965,9 @@ namespace Microsoft.AspNet.Mvc.Description
|
|||
{
|
||||
action.Parameters.Add(new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = parameter.GetCustomAttributes().OfType<IBinderMetadata>().FirstOrDefault(),
|
||||
Name = parameter.Name,
|
||||
ParameterType = parameter.ParameterType,
|
||||
BindingInfo = BindingInfo.GetBindingInfo(parameter.GetCustomAttributes().OfType<object>())
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -48,109 +49,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetModelBindingContext_ReturnsOnlyIncludedProperties_UsingBindAttributeInclude()
|
||||
{
|
||||
// Arrange
|
||||
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForType(
|
||||
typeof(TypeWithIncludedPropertiesUsingBindAttribute));
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
modelMetadata,
|
||||
new ModelStateDictionary(),
|
||||
Mock.Of<OperationBindingContext>());
|
||||
|
||||
// Assert
|
||||
Assert.True(context.PropertyFilter(context, "IncludedExplicitly1"));
|
||||
Assert.True(context.PropertyFilter(context, "IncludedExplicitly2"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetModelBindingContext_UsesBindAttributeOnType_IfNoBindAttributeOnParameter_ForPrefix()
|
||||
{
|
||||
// Arrange
|
||||
var type = typeof(ControllerActionArgumentBinderTests);
|
||||
var methodInfo = type.GetMethod("ParameterWithNoBindAttribute");
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "parameter").Single();
|
||||
|
||||
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
modelMetadata,
|
||||
new ModelStateDictionary(),
|
||||
Mock.Of<OperationBindingContext>());
|
||||
|
||||
// Assert
|
||||
Assert.Equal("TypePrefix", context.ModelName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("ParameterHasFieldPrefix", false, "simpleModelPrefix")]
|
||||
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
|
||||
[InlineData("ParameterHasPrefixAndComplexType", false, "simpleModelPrefix")]
|
||||
[InlineData("ParameterHasEmptyBindAttribute", true, "parameter")]
|
||||
public void GetModelBindingContext_ModelBindingContextIsSetWithModelName_ForParameters(
|
||||
string actionMethodName,
|
||||
bool expectedFallToEmptyPrefix,
|
||||
string expectedModelName)
|
||||
{
|
||||
// Arrange
|
||||
var type = typeof(ControllerActionArgumentBinderTests);
|
||||
var methodInfo = type.GetMethod(actionMethodName);
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "parameter").Single();
|
||||
|
||||
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
modelMetadata,
|
||||
new ModelStateDictionary(),
|
||||
Mock.Of<OperationBindingContext>());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
|
||||
Assert.Equal(expectedModelName, context.ModelName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
|
||||
[InlineData("ParameterHasPrefixAndComplexType", false, "simpleModelPrefix")]
|
||||
[InlineData("ParameterHasEmptyBindAttribute", true, "parameter1")]
|
||||
public void GetModelBindingContext_ModelBindingContextIsNotSet_ForTypes(
|
||||
string actionMethodName,
|
||||
bool expectedFallToEmptyPrefix,
|
||||
string expectedModelName)
|
||||
{
|
||||
// Arrange
|
||||
var type = typeof(ControllerActionArgumentBinderTests);
|
||||
var methodInfo = type.GetMethod(actionMethodName);
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "parameter1").Single();
|
||||
|
||||
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var modelMetadata = metadataProvider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Act
|
||||
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
|
||||
modelMetadata,
|
||||
new ModelStateDictionary(),
|
||||
Mock.Of<OperationBindingContext>());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
|
||||
Assert.Equal(expectedModelName, context.ModelName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetActionArgumentsAsync_DoesNotAddActionArguments_IfBinderReturnsFalse()
|
||||
{
|
||||
|
|
@ -165,6 +63,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
Name = "foo",
|
||||
ParameterType = typeof(object),
|
||||
BindingInfo = new BindingInfo(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -215,6 +114,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
Name = "foo",
|
||||
ParameterType = typeof(object),
|
||||
BindingInfo = new BindingInfo(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -266,6 +166,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
Name = "foo",
|
||||
ParameterType = typeof(string),
|
||||
BindingInfo = new BindingInfo(),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
@ -322,6 +223,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
Name = "foo",
|
||||
ParameterType = typeof(object),
|
||||
BindingInfo = new BindingInfo(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -375,6 +277,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
Name = "foo",
|
||||
ParameterType = typeof(object),
|
||||
BindingInfo = new BindingInfo(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -423,6 +326,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
{
|
||||
Name = "foo",
|
||||
ParameterType = typeof(object),
|
||||
BindingInfo = new BindingInfo(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -898,7 +898,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindAttribute_DoesNotUseTypePrefix()
|
||||
public async Task BindAttribute_FallsBackOnTypePrefixIfNoParameterPrefixIsProvided()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
|
|
@ -906,24 +906,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
|
||||
// Act
|
||||
var response = await client.GetStringAsync("http://localhost/BindAttribute/" +
|
||||
"TypePrefixIsNeverUsed" +
|
||||
"?param.Value=someValue");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("someValue", response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindAttribute_FallsBackOnEmptyPrefixIfNoParameterPrefixIsProvided()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetStringAsync("http://localhost/BindAttribute/" +
|
||||
"TypePrefixIsNeverUsed" +
|
||||
"?Value=someValue");
|
||||
"TypePrefixIsUsed" +
|
||||
"?TypePrefix.Value=someValue");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("someValue", response);
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
ValueProvider = Mock.Of<IValueProvider>(),
|
||||
ModelState = new ModelStateDictionary(),
|
||||
OperationBindingContext = operationBindingContext,
|
||||
BinderType = binderType
|
||||
};
|
||||
|
||||
return bindingContext;
|
||||
|
|
|
|||
|
|
@ -74,9 +74,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
// Arrange
|
||||
var provider = new TestModelMetadataProvider();
|
||||
provider.ForType<string>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
||||
|
||||
var context = new ModelBindingContext();
|
||||
context.ModelMetadata = provider.GetMetadataForType(typeof(string));
|
||||
var modelMetadata = provider.GetMetadataForType(typeof(string));
|
||||
var context = new ModelBindingContext()
|
||||
{
|
||||
ModelMetadata = modelMetadata,
|
||||
BindingSource = modelMetadata.BindingSource,
|
||||
BinderModelName = modelMetadata.BinderModelName
|
||||
};
|
||||
|
||||
var binder = new TestableBindingSourceModelBinder(BindingSource.Body);
|
||||
|
||||
|
|
|
|||
|
|
@ -76,17 +76,19 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
{
|
||||
var metadataProvider = new TestModelMetadataProvider();
|
||||
metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header);
|
||||
|
||||
var modelMetadata = metadataProvider.GetMetadataForType(modelType);
|
||||
var bindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
|
||||
ModelMetadata = modelMetadata,
|
||||
ModelName = "modelName",
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
ModelBinder = new HeaderModelBinder(),
|
||||
MetadataProvider = metadataProvider,
|
||||
HttpContext = new DefaultHttpContext()
|
||||
}
|
||||
},
|
||||
BinderModelName = modelMetadata.BinderModelName,
|
||||
BindingSource = modelMetadata.BindingSource,
|
||||
};
|
||||
|
||||
return bindingContext;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
||||
|
|
@ -8,24 +10,38 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
public class ModelBindingContextTest
|
||||
{
|
||||
[Fact]
|
||||
public void CopyConstructor()
|
||||
public void GetChildModelBindingContext()
|
||||
{
|
||||
// Arrange
|
||||
var originalBindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
|
||||
ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)),
|
||||
ModelName = "theName",
|
||||
ModelState = new ModelStateDictionary(),
|
||||
ValueProvider = new SimpleHttpValueProvider()
|
||||
};
|
||||
|
||||
var newModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(object));
|
||||
var metadataProvider = new TestModelMetadataProvider();
|
||||
metadataProvider.ForType<object>().BindingDetails(d =>
|
||||
{
|
||||
d.BindingSource = BindingSource.Custom;
|
||||
d.BinderType = typeof(TestModelBinder);
|
||||
d.BinderModelName = "custom";
|
||||
});
|
||||
|
||||
var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object));
|
||||
|
||||
// Act
|
||||
var newBindingContext = new ModelBindingContext(originalBindingContext, string.Empty, newModelMetadata);
|
||||
var newBindingContext = ModelBindingContext.GetChildModelBindingContext(
|
||||
originalBindingContext,
|
||||
string.Empty,
|
||||
newModelMetadata);
|
||||
|
||||
// Assert
|
||||
Assert.Same(newModelMetadata, newBindingContext.ModelMetadata);
|
||||
Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource);
|
||||
Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName);
|
||||
Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType);
|
||||
Assert.Equal("", newBindingContext.ModelName);
|
||||
Assert.Equal(originalBindingContext.ModelState, newBindingContext.ModelState);
|
||||
Assert.Equal(originalBindingContext.ValueProvider, newBindingContext.ValueProvider);
|
||||
|
|
@ -43,5 +59,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
// Assert
|
||||
Assert.Equal(typeof(int), bindingContext.ModelType);
|
||||
}
|
||||
|
||||
private class TestModelBinder : IModelBinder
|
||||
{
|
||||
public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,11 +32,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
.Returns(Task.FromResult(false));
|
||||
|
||||
var metadataProvider = new TestModelMetadataProvider();
|
||||
if (isPrefixProvided)
|
||||
{
|
||||
metadataProvider.ForType<Person>().BindingDetails(bd => bd.BinderModelName = "prefix");
|
||||
}
|
||||
|
||||
var bindingContext = new MutableObjectBinderContext
|
||||
{
|
||||
ModelBindingContext = new ModelBindingContext
|
||||
|
|
@ -53,6 +48,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
// Setting it to empty ensures that model does not get created becasue of no model name.
|
||||
ModelName = "dummyModelName",
|
||||
BinderModelName = isPrefixProvided ? "prefix" : null,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -110,6 +106,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
[Fact]
|
||||
public async Task CanCreateModel_ReturnsFalse_ForNonTopLevelModel_IfModelIsMarkedWithBinderMetadata()
|
||||
{
|
||||
var modelMetadata = GetMetadataForType(typeof(Document))
|
||||
.Properties
|
||||
.First(metadata => metadata.PropertyName == nameof(Document.SubDocument));
|
||||
var bindingContext = new MutableObjectBinderContext
|
||||
{
|
||||
ModelBindingContext = new ModelBindingContext
|
||||
|
|
@ -121,7 +120,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
|
||||
}
|
||||
},
|
||||
BindingSource = modelMetadata.BindingSource,
|
||||
BinderModelName = modelMetadata.BinderModelName,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -265,12 +266,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
|
||||
return null;
|
||||
});
|
||||
|
||||
|
||||
var modelMetadata = GetMetadataForType(modelType);
|
||||
var bindingContext = new MutableObjectBinderContext
|
||||
{
|
||||
ModelBindingContext = new ModelBindingContext
|
||||
{
|
||||
ModelMetadata = GetMetadataForType(modelType),
|
||||
ModelMetadata = modelMetadata,
|
||||
ValueProvider = mockValueProvider.Object,
|
||||
OperationBindingContext = new OperationBindingContext
|
||||
{
|
||||
|
|
@ -280,7 +282,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
},
|
||||
|
||||
// Setting it to empty ensures that model does not get created becasue of no model name.
|
||||
ModelName = "dummyName"
|
||||
ModelName = "dummyName",
|
||||
BindingSource = modelMetadata.BindingSource,
|
||||
BinderModelName = modelMetadata.BinderModelName
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBindingDetails_FindsModelName_IfEmpty()
|
||||
public void GetBindingDetails_FindsModelName_IfNullFallsBack()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new object[]
|
||||
|
|
@ -98,7 +98,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
provider.GetBindingMetadata(context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(context.BindingMetadata.BinderModelName);
|
||||
Assert.Equal("Product", context.BindingMetadata.BinderModelName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -110,66 +110,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
Assert.Equal("OnPropertyType", Assert.IsType<ModelAttribute>(attributes[1]).Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForParameter_IncludesMergedAttributes()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider();
|
||||
|
||||
var methodInfo = GetType().GetMethod(
|
||||
"GetMetadataForParameterTestMethod",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "parameter").Single();
|
||||
|
||||
var additionalAttributes = new object[]
|
||||
{
|
||||
new ModelAttribute("Extra"),
|
||||
};
|
||||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForParameter(parameterInfo, additionalAttributes);
|
||||
|
||||
// Assert
|
||||
var defaultMetadata = Assert.IsType<DefaultModelMetadata>(metadata);
|
||||
|
||||
var attributes = defaultMetadata.Attributes.ToArray();
|
||||
Assert.Equal("Extra", Assert.IsType<ModelAttribute>(attributes[0]).Value);
|
||||
Assert.Equal("OnParameter", Assert.IsType<ModelAttribute>(attributes[1]).Value);
|
||||
Assert.Equal("OnType", Assert.IsType<ModelAttribute>(attributes[2]).Value);
|
||||
}
|
||||
|
||||
// The 'attributes' are assumed to be the same every time. We can safely omit them after
|
||||
// the first call.
|
||||
[Fact]
|
||||
public void GetMetadataForParameter_Cached()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider();
|
||||
|
||||
var methodInfo = GetType().GetMethod(
|
||||
"GetMetadataForParameterTestMethod",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
var additionalAttributes = new object[]
|
||||
{
|
||||
new ModelAttribute("Extra"),
|
||||
};
|
||||
|
||||
// Act
|
||||
var metadata1 = Assert.IsType<DefaultModelMetadata>(provider.GetMetadataForParameter(
|
||||
methodInfo.GetParameters().Where(p => p.Name == "parameter").Single(),
|
||||
additionalAttributes));
|
||||
var metadata2 = Assert.IsType<DefaultModelMetadata>(provider.GetMetadataForParameter(
|
||||
methodInfo.GetParameters().Where(p => p.Name == "parameter").Single(),
|
||||
attributes: null));
|
||||
|
||||
// Assert
|
||||
Assert.Same(metadata1.Attributes, metadata2.Attributes);
|
||||
Assert.Same(metadata1.BindingMetadata, metadata2.BindingMetadata);
|
||||
Assert.Same(metadata1.DisplayMetadata, metadata2.DisplayMetadata);
|
||||
Assert.Same(metadata1.ValidationMetadata, metadata2.ValidationMetadata);
|
||||
}
|
||||
|
||||
private static DefaultModelMetadataProvider CreateProvider()
|
||||
{
|
||||
return new DefaultModelMetadataProvider(new EmptyCompositeMetadataDetailsProvider());
|
||||
|
|
|
|||
|
|
@ -43,103 +43,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
Assert.Equal<string>(expected, matched);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelMetadataProvider_UsesPredicateOnParameter()
|
||||
{
|
||||
// Arrange
|
||||
var type = GetType();
|
||||
var methodInfo = type.GetMethod(
|
||||
"ActionWithoutBindAttribute",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "param").Single();
|
||||
|
||||
var provider = CreateProvider();
|
||||
var context = new ModelBindingContext();
|
||||
|
||||
// Note it does an intersection for included -- only properties that
|
||||
// pass both predicates will be bound.
|
||||
var expected = new[] { "IsAdmin", "UserName" };
|
||||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Assert
|
||||
var predicate = metadata.PropertyBindingPredicateProvider.PropertyFilter;
|
||||
Assert.NotNull(predicate);
|
||||
|
||||
var matched = new HashSet<string>();
|
||||
foreach (var property in metadata.Properties)
|
||||
{
|
||||
if (predicate(context, property.PropertyName))
|
||||
{
|
||||
matched.Add(property.PropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.Equal<string>(expected, matched);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelMetadataProvider_UsesPredicateOnParameter_Merge()
|
||||
{
|
||||
// Arrange
|
||||
var type = GetType();
|
||||
var methodInfo = type.GetMethod(
|
||||
"ActionWithBindAttribute",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "param").Single();
|
||||
|
||||
var provider = CreateProvider();
|
||||
var context = new ModelBindingContext();
|
||||
|
||||
// Note it does an intersection for included -- only properties that
|
||||
// pass both predicates will be bound.
|
||||
var expected = new[] { "IsAdmin" };
|
||||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Assert
|
||||
var predicate = metadata.PropertyBindingPredicateProvider.PropertyFilter;
|
||||
Assert.NotNull(predicate);
|
||||
|
||||
var matched = new HashSet<string>();
|
||||
foreach (var property in metadata.Properties)
|
||||
{
|
||||
if (predicate(context, property.PropertyName))
|
||||
{
|
||||
matched.Add(property.PropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.Equal<string>(expected, matched);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelMetadataProvider_ReadsModelNameProperty_ForParameters()
|
||||
{
|
||||
// Arrange
|
||||
var type = GetType();
|
||||
var methodInfo = type.GetMethod(
|
||||
"ActionWithBindAttribute",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "param").Single();
|
||||
|
||||
var provider = CreateProvider();
|
||||
|
||||
// Act
|
||||
var metadata = provider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("ParameterPrefix", metadata.BinderModelName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ModelMetadataProvider_ReadsModelNameProperty_ForTypes()
|
||||
{
|
||||
|
|
@ -267,60 +170,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
Assert.Equal("GrandParentProperty", propertyMetadata.BinderModelName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForParameter_WithNoBinderMetadata_GetsItFromType()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider();
|
||||
|
||||
var methodInfo = typeof(Person).GetMethod("Update");
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "person").Single();
|
||||
|
||||
// Act
|
||||
var parameterMetadata = provider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("PersonType", parameterMetadata.BinderModelName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForParameter_WithBinderDataOnParameterAndType_GetsMetadataFromParameter()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider();
|
||||
|
||||
var methodInfo = typeof(Person).GetMethod("Save");
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "person").Single();
|
||||
|
||||
// Act
|
||||
var parameterMetadata = provider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: null);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("PersonParameter", parameterMetadata.BinderModelName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMetadataForParameter_BinderModelNameOverride()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider();
|
||||
|
||||
var methodInfo = typeof(Person).GetMethod("Save");
|
||||
var parameterInfo = methodInfo.GetParameters().Where(p => p.Name == "person").Single();
|
||||
|
||||
// Act
|
||||
var parameterMetadata = provider.GetMetadataForParameter(
|
||||
parameterInfo,
|
||||
attributes: new object[] { new ModelBinderAttribute() { Name = "Override" } });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Override", parameterMetadata.BinderModelName);
|
||||
}
|
||||
|
||||
public static TheoryData<object, Func<ModelMetadata, string>> ExpectedAttributeDataStrings
|
||||
{
|
||||
get
|
||||
|
|
@ -780,12 +629,12 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
|
|||
{
|
||||
}
|
||||
|
||||
public class TypeBasedBinderAttribute : Attribute, IBinderMetadata, IModelNameProvider
|
||||
public class TypeBasedBinderAttribute : Attribute, IModelNameProvider
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
public class NonTypeBasedBinderAttribute : Attribute, IBinderMetadata, IModelNameProvider
|
||||
public class NonTypeBasedBinderAttribute : Attribute, IModelNameProvider
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +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.
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||
{
|
||||
public class TestBinderMetadata : IBinderMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,38 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("CompareAttributeTestResource"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// description from resources
|
||||
/// </summary>
|
||||
internal static string DisplayAttribute_Description
|
||||
{
|
||||
get { return GetString("DisplayAttribute_Description"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// description from resources
|
||||
/// </summary>
|
||||
internal static string FormatDisplayAttribute_Description()
|
||||
{
|
||||
return GetString("DisplayAttribute_Description");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// name from resources
|
||||
/// </summary>
|
||||
internal static string DisplayAttribute_Name
|
||||
{
|
||||
get { return GetString("DisplayAttribute_Name"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// name from resources
|
||||
/// </summary>
|
||||
internal static string FormatDisplayAttribute_Name()
|
||||
{
|
||||
return GetString("DisplayAttribute_Name");
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Mvc;
|
|||
using Microsoft.AspNet.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.WebApiCompatShim;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
|
@ -276,8 +277,9 @@ namespace System.Web.Http
|
|||
foreach (var action in actions)
|
||||
{
|
||||
var parameter = Assert.Single(action.Parameters);
|
||||
var metadata = Assert.IsType<FromUriAttribute>(parameter.BinderMetadata);
|
||||
Assert.False(metadata.IsOptional);
|
||||
Assert.Equal((new FromUriAttribute()).BindingSource, parameter.BindingInfo.BindingSource);
|
||||
var optionalParameters = (HashSet<string>)action.Properties["OptionalParameters"];
|
||||
Assert.False(optionalParameters.Contains(parameter.Name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,12 +306,12 @@ namespace System.Web.Http
|
|||
foreach (var action in actions)
|
||||
{
|
||||
var parameter = Assert.Single(action.Parameters);
|
||||
Assert.IsType<FromBodyAttribute>(parameter.BinderMetadata);
|
||||
Assert.Equal(BindingSource.Body, parameter.BindingInfo.BindingSource);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetActions_Parameters_BinderMetadata()
|
||||
public void GetActions_Parameters_WithBindingSource()
|
||||
{
|
||||
// Arrange
|
||||
var provider = CreateProvider();
|
||||
|
|
@ -331,7 +333,7 @@ namespace System.Web.Http
|
|||
foreach (var action in actions)
|
||||
{
|
||||
var parameter = Assert.Single(action.Parameters);
|
||||
Assert.IsType<ModelBinderAttribute>(parameter.BinderMetadata);
|
||||
Assert.Null(parameter.BindingInfo.BindingSource);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -360,8 +362,9 @@ namespace System.Web.Http
|
|||
foreach (var action in actions)
|
||||
{
|
||||
var parameter = Assert.Single(action.Parameters);
|
||||
var metadata = Assert.IsType<FromUriAttribute>(parameter.BinderMetadata);
|
||||
Assert.True(metadata.IsOptional);
|
||||
Assert.Equal((new FromUriAttribute()).BindingSource, parameter.BindingInfo.BindingSource);
|
||||
var optionalParameters = (HashSet<string>)action.Properties["OptionalParameters"];
|
||||
Assert.True(optionalParameters.Contains(parameter.Name));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||
using System.Web.Http;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -21,7 +22,10 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -51,13 +55,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -87,13 +97,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -123,13 +139,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -159,18 +181,28 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute() { IsOptional = true },
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
};
|
||||
|
||||
var optionalParameters = new HashSet<string>();
|
||||
optionalParameters.Add("quantity");
|
||||
|
||||
action.Properties.Add("OptionalParameters", optionalParameters);
|
||||
var constraint = new OverloadActionConstraint();
|
||||
|
||||
var context = new ActionConstraintContext();
|
||||
|
|
@ -195,13 +227,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -212,13 +250,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity_ordered",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -252,7 +296,10 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -263,13 +310,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -300,30 +353,46 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute() { IsOptional = true },
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
};
|
||||
|
||||
var optionalParameters = new HashSet<string>();
|
||||
optionalParameters.Add("quantity");
|
||||
action1.Properties.Add("OptionalParameters", optionalParameters);
|
||||
|
||||
var action2 = new ActionDescriptor();
|
||||
action2.Parameters = new List<ParameterDescriptor>()
|
||||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -354,13 +423,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -371,13 +446,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "price",
|
||||
ParameterType = typeof(decimal),
|
||||
},
|
||||
|
|
@ -411,7 +492,10 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -422,18 +506,28 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute() { IsOptional = true },
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
};
|
||||
|
||||
var optionalParameters = new HashSet<string>();
|
||||
optionalParameters.Add("quantity");
|
||||
action2.Properties.Add("OptionalParameters", optionalParameters);
|
||||
|
||||
var constraint = new OverloadActionConstraint();
|
||||
|
||||
var context = new ActionConstraintContext();
|
||||
|
|
@ -459,7 +553,10 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
@ -470,13 +567,19 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
|
|||
{
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromUriAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromUriAttribute()).BindingSource,
|
||||
},
|
||||
Name = "id",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
new ParameterDescriptor()
|
||||
{
|
||||
BinderMetadata = new FromBodyAttribute(),
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BindingSource = (new FromBodyAttribute()).BindingSource,
|
||||
},
|
||||
Name = "quantity",
|
||||
ParameterType = typeof(int),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -16,19 +16,16 @@ namespace ApplicationModelWebSite
|
|||
{
|
||||
public string GetParameterMetadata([Cool] int? id)
|
||||
{
|
||||
return ActionContext.ActionDescriptor.Parameters[0].BinderMetadata.GetType().Name;
|
||||
return ActionContext.ActionDescriptor.Parameters[0].BindingInfo.BinderModelName;
|
||||
}
|
||||
|
||||
private class CoolAttribute : Attribute, IParameterModelConvention
|
||||
{
|
||||
public void Apply(ParameterModel model)
|
||||
{
|
||||
model.BinderMetadata = new CoolMetadata();
|
||||
model.BindingInfo.BindingSource = BindingSource.Custom;
|
||||
model.BindingInfo.BinderModelName = "CoolMetadata";
|
||||
}
|
||||
}
|
||||
|
||||
private class CoolMetadata : IBinderMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>94ba134d-04b3-48aa-ba55-5a4db8640f2d</ProjectGuid>
|
||||
<ProjectGuid>b42d4844-fff8-4ec2-88d1-3ae95234d9eb</ProjectGuid>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ namespace FormatterWebSite
|
|||
{
|
||||
var bodyParameter = context.ActionDescriptor
|
||||
.Parameters
|
||||
.FirstOrDefault(parameter => IsBodyBindingSource(parameter.BinderMetadata));
|
||||
.FirstOrDefault(parameter => IsBodyBindingSource(
|
||||
parameter.BindingInfo.BindingSource));
|
||||
if (bodyParameter != null)
|
||||
{
|
||||
var parameterBindingErrors = context.ModelState[bodyParameter.Name].Errors;
|
||||
|
|
@ -37,9 +38,8 @@ namespace FormatterWebSite
|
|||
base.OnActionExecuting(context);
|
||||
}
|
||||
|
||||
private bool IsBodyBindingSource(IBinderMetadata binderMetadata)
|
||||
private bool IsBodyBindingSource(BindingSource bindingSource)
|
||||
{
|
||||
var bindingSource = (binderMetadata as IBindingSourceMetadata)?.BindingSource;
|
||||
return bindingSource?.CanAcceptDataFrom(BindingSource.Body) ?? false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ namespace ModelBindingWebSite.Controllers
|
|||
return param.Value;
|
||||
}
|
||||
|
||||
// This will use param to try to bind and not the value specified at TypePrefix.
|
||||
public string TypePrefixIsNeverUsed([Bind] TypePrefix param)
|
||||
public string TypePrefixIsUsed([Bind] TypePrefix param)
|
||||
{
|
||||
return param.Value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,14 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
|
||||
namespace ModelBindingWebSite
|
||||
{
|
||||
public class FromNonExistantBinderAttribute : Attribute, IBinderMetadata
|
||||
public class FromNonExistantBinderAttribute : Attribute, IBindingSourceMetadata
|
||||
{
|
||||
public BindingSource BindingSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return BindingSource.Custom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue