Skip to content

Commit

Permalink
Adds ActionContext to Validation contexts
Browse files Browse the repository at this point in the history
This change makes it possible to access the ActionContext/ActionDescriptor
from inside of validators and client validators.
  • Loading branch information
rynowak committed Nov 26, 2015
1 parent 017bf1a commit d8cc2b8
Show file tree
Hide file tree
Showing 42 changed files with 658 additions and 689 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public ModelBindingContext()
/// <returns>A new instance of <see cref="ModelBindingContext"/>.</returns>
public static ModelBindingContext CreateBindingContext(
OperationBindingContext operationBindingContext,
ModelStateDictionary modelState,
ModelMetadata metadata,
BindingInfo bindingInfo,
string modelName)
Expand All @@ -47,11 +46,6 @@ public static ModelBindingContext CreateBindingContext(
throw new ArgumentNullException(nameof(operationBindingContext));
}

if (modelState == null)
{
throw new ArgumentNullException(nameof(modelState));
}

if (metadata == null)
{
throw new ArgumentNullException(nameof(metadata));
Expand Down Expand Up @@ -83,7 +77,7 @@ public static ModelBindingContext CreateBindingContext(

IsTopLevelObject = true,
ModelMetadata = metadata,
ModelState = modelState,
ModelState = operationBindingContext.ActionContext.ModelState,
OperationBindingContext = operationBindingContext,
ValueProvider = operationBindingContext.ValueProvider,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
public class ClientModelValidationContext
{
public ClientModelValidationContext(
ActionContext actionContext,
ModelMetadata metadata,
IModelMetadataProvider metadataProvider,
IServiceProvider requestServices)
IModelMetadataProvider metadataProvider)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}

if (metadata == null)
{
throw new ArgumentNullException(nameof(metadata));
Expand All @@ -22,20 +27,15 @@ public ClientModelValidationContext(
throw new ArgumentNullException(nameof(metadataProvider));
}

if (requestServices == null)
{
throw new ArgumentNullException(nameof(requestServices));
}

ActionContext = actionContext;
ModelMetadata = metadata;
MetadataProvider = metadataProvider;
RequestServices = requestServices;
}

public ActionContext ActionContext { get; }

public ModelMetadata ModelMetadata { get; }

public IModelMetadataProvider MetadataProvider { get; }

public IServiceProvider RequestServices { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation
/// </summary>
public class ModelValidationContext
{
/// <summary>
/// Gets or sets the <see cref="Mvc.ActionContext"/>
/// </summary>
public ActionContext ActionContext { get; set; }

/// <summary>
/// Gets or sets the model object.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ private async Task<IDictionary<string, object>> BindActionArgumentsCoreAsync(
var controllerProperties = new Dictionary<string, object>(StringComparer.Ordinal);
await PopulateArgumentsAsync(
operationBindingContext,
context.ModelState,
controllerProperties,
actionDescriptor.BoundProperties);
var controllerType = actionDescriptor.ControllerTypeInfo.AsType();
Expand All @@ -91,27 +90,20 @@ await PopulateArgumentsAsync(
var actionArguments = new Dictionary<string, object>(StringComparer.Ordinal);
await PopulateArgumentsAsync(
operationBindingContext,
context.ModelState,
actionArguments,
actionDescriptor.Parameters);
return actionArguments;
}

public async Task<ModelBindingResult> BindModelAsync(
ParameterDescriptor parameter,
ModelStateDictionary modelState,
OperationBindingContext operationContext)
{
if (parameter == null)
{
throw new ArgumentNullException(nameof(parameter));
}

if (modelState == null)
{
throw new ArgumentNullException(nameof(modelState));
}

if (operationContext == null)
{
throw new ArgumentNullException(nameof(operationContext));
Expand All @@ -120,7 +112,6 @@ public async Task<ModelBindingResult> BindModelAsync(
var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterType);
var modelBindingContext = ModelBindingContext.CreateBindingContext(
operationContext,
modelState,
metadata,
parameter.BindingInfo,
parameter.Name);
Expand All @@ -129,8 +120,8 @@ public async Task<ModelBindingResult> BindModelAsync(
if (modelBindingResult.IsModelSet)
{
_validator.Validate(
operationContext.ActionContext,
operationContext.ValidatorProvider,
modelState,
modelBindingContext.ValidationState,
modelBindingResult.Key,
modelBindingResult.Model);
Expand Down Expand Up @@ -204,15 +195,14 @@ private void ActivateProperties(object controller, Type containerType, Dictionar

private async Task PopulateArgumentsAsync(
OperationBindingContext operationContext,
ModelStateDictionary modelState,
IDictionary<string, object> arguments,
IList<ParameterDescriptor> parameterMetadata)
{
// Perf: Avoid allocations
for (var i = 0; i < parameterMetadata.Count; i++)
{
var parameter = parameterMetadata[i];
var modelBindingResult = await BindModelAsync(parameter, modelState, operationContext);
var modelBindingResult = await BindModelAsync(parameter, operationContext);
if (modelBindingResult.IsModelSet)
{
arguments[parameter.Name] = modelBindingResult.Model;
Expand Down
90 changes: 23 additions & 67 deletions src/Microsoft.AspNet.Mvc.Core/ModelBinding/ModelBindingHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ public static class ModelBindingHelper
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="actionContext">The <see cref="ActionContext"/> for the current executing request.</param>
/// <param name="modelState">The <see cref="ModelStateDictionary"/> used for maintaining state and
/// results of model-binding validation.</param>
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
Expand All @@ -46,7 +44,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
TModel model,
string prefix,
ActionContext actionContext,
ModelStateDictionary modelState,
IModelMetadataProvider metadataProvider,
IModelBinder modelBinder,
IValueProvider valueProvider,
Expand All @@ -70,11 +67,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
throw new ArgumentNullException(nameof(actionContext));
}

if (modelState == null)
{
throw new ArgumentNullException(nameof(modelState));
}

if (metadataProvider == null)
{
throw new ArgumentNullException(nameof(metadataProvider));
Expand Down Expand Up @@ -110,7 +102,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
model,
prefix,
actionContext,
modelState,
metadataProvider,
modelBinder,
valueProvider,
Expand All @@ -130,8 +121,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="actionContext">The <see cref="ActionContext"/> for the current executing request.</param>
/// <param name="modelState">The <see cref="ModelStateDictionary"/> used for maintaining state and
/// results of model-binding validation.</param>
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
Expand All @@ -147,17 +136,16 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
/// which need to be included for the current model.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
public static Task<bool> TryUpdateModelAsync<TModel>(
TModel model,
string prefix,
ActionContext actionContext,
ModelStateDictionary modelState,
IModelMetadataProvider metadataProvider,
IModelBinder modelBinder,
IValueProvider valueProvider,
IList<IInputFormatter> inputFormatters,
IObjectModelValidator objectModelValidator,
IModelValidatorProvider validatorProvider,
params Expression<Func<TModel, object>>[] includeExpressions)
TModel model,
string prefix,
ActionContext actionContext,
IModelMetadataProvider metadataProvider,
IModelBinder modelBinder,
IValueProvider valueProvider,
IList<IInputFormatter> inputFormatters,
IObjectModelValidator objectModelValidator,
IModelValidatorProvider validatorProvider,
params Expression<Func<TModel, object>>[] includeExpressions)
where TModel : class
{
if (model == null)
Expand All @@ -175,11 +163,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
throw new ArgumentNullException(nameof(actionContext));
}

if (modelState == null)
{
throw new ArgumentNullException(nameof(modelState));
}

if (metadataProvider == null)
{
throw new ArgumentNullException(nameof(metadataProvider));
Expand Down Expand Up @@ -222,7 +205,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
model,
prefix,
actionContext,
modelState,
metadataProvider,
modelBinder,
valueProvider,
Expand All @@ -242,8 +224,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="actionContext">The <see cref="ActionContext"/> for the current executing request.</param>
/// <param name="modelState">The <see cref="ModelStateDictionary"/> used for maintaining state and
/// results of model-binding validation.</param>
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
Expand All @@ -258,18 +238,17 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
/// filter properties(for inclusion/exclusion) at runtime.</param>
/// <returns>A <see cref="Task"/> that on completion returns <c>true</c> if the update is successful</returns>
public static Task<bool> TryUpdateModelAsync<TModel>(
TModel model,
string prefix,
ActionContext actionContext,
ModelStateDictionary modelState,
IModelMetadataProvider metadataProvider,
IModelBinder modelBinder,
IValueProvider valueProvider,
IList<IInputFormatter> inputFormatters,
IObjectModelValidator objectModelValidator,
IModelValidatorProvider validatorProvider,
Func<ModelBindingContext, string, bool> predicate)
where TModel : class
TModel model,
string prefix,
ActionContext actionContext,
IModelMetadataProvider metadataProvider,
IModelBinder modelBinder,
IValueProvider valueProvider,
IList<IInputFormatter> inputFormatters,
IObjectModelValidator objectModelValidator,
IModelValidatorProvider validatorProvider,
Func<ModelBindingContext, string, bool> predicate)
where TModel : class
{
if (model == null)
{
Expand All @@ -286,11 +265,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
throw new ArgumentNullException(nameof(actionContext));
}

if (modelState == null)
{
throw new ArgumentNullException(nameof(modelState));
}

if (metadataProvider == null)
{
throw new ArgumentNullException(nameof(metadataProvider));
Expand Down Expand Up @@ -331,7 +305,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
typeof(TModel),
prefix,
actionContext,
modelState,
metadataProvider,
modelBinder,
valueProvider,
Expand All @@ -351,8 +324,6 @@ public static Task<bool> TryUpdateModelAsync<TModel>(
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="actionContext">The <see cref="ActionContext"/> for the current executing request.</param>
/// <param name="modelState">The <see cref="ModelStateDictionary"/> used for maintaining state and
/// results of model-binding validation.</param>
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
Expand All @@ -369,7 +340,6 @@ public static Task<bool> TryUpdateModelAsync(
Type modelType,
string prefix,
ActionContext actionContext,
ModelStateDictionary modelState,
IModelMetadataProvider metadataProvider,
IModelBinder modelBinder,
IValueProvider valueProvider,
Expand Down Expand Up @@ -397,11 +367,6 @@ public static Task<bool> TryUpdateModelAsync(
throw new ArgumentNullException(nameof(actionContext));
}

if (modelState == null)
{
throw new ArgumentNullException(nameof(modelState));
}

if (metadataProvider == null)
{
throw new ArgumentNullException(nameof(metadataProvider));
Expand Down Expand Up @@ -438,7 +403,6 @@ public static Task<bool> TryUpdateModelAsync(
modelType,
prefix,
actionContext,
modelState,
metadataProvider,
modelBinder,
valueProvider,
Expand All @@ -458,8 +422,6 @@ public static Task<bool> TryUpdateModelAsync(
/// <param name="prefix">The prefix to use when looking up values in the <paramref name="valueProvider"/>.
/// </param>
/// <param name="actionContext">The <see cref="ActionContext"/> for the current executing request.</param>
/// <param name="modelState">The <see cref="ModelStateDictionary"/> used for maintaining state and
/// results of model-binding validation.</param>
/// <param name="metadataProvider">The provider used for reading metadata for the model type.</param>
/// <param name="modelBinder">The <see cref="IModelBinder"/> used for binding.</param>
/// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param>
Expand All @@ -478,7 +440,6 @@ public static async Task<bool> TryUpdateModelAsync(
Type modelType,
string prefix,
ActionContext actionContext,
ModelStateDictionary modelState,
IModelMetadataProvider metadataProvider,
IModelBinder modelBinder,
IValueProvider valueProvider,
Expand Down Expand Up @@ -507,11 +468,6 @@ public static async Task<bool> TryUpdateModelAsync(
throw new ArgumentNullException(nameof(actionContext));
}

if (modelState == null)
{
throw new ArgumentNullException(nameof(modelState));
}

if (metadataProvider == null)
{
throw new ArgumentNullException(nameof(metadataProvider));
Expand Down Expand Up @@ -558,6 +514,7 @@ public static async Task<bool> TryUpdateModelAsync(
var modelMetadata = metadataProvider.GetMetadataForType(modelType);

// Clear ModelStateDictionary entries for the model so that it will be re-validated.
var modelState = actionContext.ModelState;
ClearValidationStateForModel(modelType, modelState, metadataProvider, prefix);

var operationBindingContext = new OperationBindingContext
Expand All @@ -572,7 +529,6 @@ public static async Task<bool> TryUpdateModelAsync(

var modelBindingContext = ModelBindingContext.CreateBindingContext(
operationBindingContext,
modelState,
modelMetadata,
bindingInfo: null,
modelName: prefix ?? string.Empty);
Expand All @@ -583,8 +539,8 @@ public static async Task<bool> TryUpdateModelAsync(
if (modelBindingResult.IsModelSet)
{
objectModelValidator.Validate(
operationBindingContext.ActionContext,
operationBindingContext.ValidatorProvider,
modelState,
modelBindingContext.ValidationState,
modelBindingResult.Key,
modelBindingResult.Model);
Expand Down
Loading

0 comments on commit d8cc2b8

Please sign in to comment.