public void EnterNestedScope_FiltersValueProviders_BasedOnTopLevelValueProviders() { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty(typeof(string), nameof(string.Length)) .BindingDetails(b => b.BindingSource = BindingSource.Form); var original = CreateDefaultValueProvider(); var operationBindingContext = new OperationBindingContext() { ActionContext = new ActionContext(), ValueProvider = original, }; var context = DefaultModelBindingContext.CreateBindingContext( operationBindingContext, metadataProvider.GetMetadataForType(typeof(string)), new BindingInfo() { BindingSource = BindingSource.Query }, "model"); var propertyMetadata = metadataProvider.GetMetadataForProperty(typeof(string), nameof(string.Length)); // Act context.EnterNestedScope(propertyMetadata, "Length", "Length", model: null); // Assert Assert.Collection( Assert.IsType <CompositeValueProvider>(context.ValueProvider), vp => Assert.Same(original[2], vp)); }
public void CreateBindingContext_FiltersValueProviders_ForValueProviderSource() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var original = CreateDefaultValueProvider(); var operationBindingContext = new OperationBindingContext() { ActionContext = new ActionContext(), ValueProvider = original, }; // Act var context = DefaultModelBindingContext.CreateBindingContext( operationBindingContext, metadataProvider.GetMetadataForType(typeof(object)), new BindingInfo() { BindingSource = BindingSource.Query }, "model"); // Assert Assert.Collection( Assert.IsType <CompositeValueProvider>(context.ValueProvider), vp => Assert.Same(original[1], vp)); }
/// <summary> /// Creates a new <see cref="DefaultModelBindingContext"/> for top-level model binding operation. /// </summary> /// <param name="operationBindingContext"> /// The <see cref="OperationBindingContext"/> associated with the binding operation. /// </param> /// <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">The name of the property or parameter being bound.</param> /// <returns>A new instance of <see cref="DefaultModelBindingContext"/>.</returns> public static ModelBindingContext CreateBindingContext( OperationBindingContext operationBindingContext, ModelMetadata metadata, BindingInfo bindingInfo, string modelName) { if (operationBindingContext == null) { throw new ArgumentNullException(nameof(operationBindingContext)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (modelName == null) { throw new ArgumentNullException(nameof(modelName)); } var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName; var propertyFilterProvider = bindingInfo?.PropertyFilterProvider ?? metadata.PropertyFilterProvider; var valueProvider = operationBindingContext.ValueProvider; var bindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource; if (bindingSource != null && !bindingSource.IsGreedy) { valueProvider = FilterValueProvider(operationBindingContext.ValueProvider, bindingSource); } return(new DefaultModelBindingContext() { BinderModelName = binderModelName, BindingSource = bindingSource, PropertyFilter = propertyFilterProvider?.PropertyFilter, // Because this is the top-level context, FieldName and ModelName should be the same. FieldName = binderModelName ?? modelName, ModelName = binderModelName ?? modelName, IsTopLevelObject = true, ModelMetadata = metadata, ModelState = operationBindingContext.ActionContext.ModelState, OperationBindingContext = operationBindingContext, ValueProvider = valueProvider, ValidationState = new ValidationStateDictionary(), }); }
/// <summary> /// Creates a new <see cref="DefaultModelBindingContext"/> for top-level model binding operation. /// </summary> /// <param name="operationBindingContext"> /// The <see cref="OperationBindingContext"/> associated with the binding operation. /// </param> /// <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">The name of the property or parameter being bound.</param> /// <returns>A new instance of <see cref="DefaultModelBindingContext"/>.</returns> public static ModelBindingContext CreateBindingContext( OperationBindingContext operationBindingContext, ModelMetadata metadata, BindingInfo bindingInfo, string modelName) { if (operationBindingContext == null) { throw new ArgumentNullException(nameof(operationBindingContext)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (modelName == null) { throw new ArgumentNullException(nameof(modelName)); } var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName; var propertyFilterProvider = bindingInfo?.PropertyFilterProvider ?? metadata.PropertyFilterProvider; var valueProvider = operationBindingContext.ValueProvider; var bindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource; if (bindingSource != null && !bindingSource.IsGreedy) { valueProvider = FilterValueProvider(operationBindingContext.ValueProvider, bindingSource); } return new DefaultModelBindingContext() { BinderModelName = binderModelName, BindingSource = bindingSource, PropertyFilter = propertyFilterProvider?.PropertyFilter, // Because this is the top-level context, FieldName and ModelName should be the same. FieldName = binderModelName ?? modelName, ModelName = binderModelName ?? modelName, IsTopLevelObject = true, ModelMetadata = metadata, ModelState = operationBindingContext.ActionContext.ModelState, OperationBindingContext = operationBindingContext, ValueProvider = valueProvider, ValidationState = new ValidationStateDictionary(), }; }
/// <summary> /// Creates a new <see cref="DefaultModelBindingContext"/> for top-level model binding operation. /// </summary> /// <param name="operationBindingContext"> /// The <see cref="OperationBindingContext"/> associated with the binding operation. /// </param> /// <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">The name of the property or parameter being bound.</param> /// <returns>A new instance of <see cref="DefaultModelBindingContext"/>.</returns> public static ModelBindingContext CreateBindingContext( OperationBindingContext operationBindingContext, ModelMetadata metadata, BindingInfo bindingInfo, string modelName) { if (operationBindingContext == null) { throw new ArgumentNullException(nameof(operationBindingContext)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (modelName == null) { throw new ArgumentNullException(nameof(modelName)); } var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName; var propertyPredicateProvider = bindingInfo?.PropertyBindingPredicateProvider ?? metadata.PropertyBindingPredicateProvider; return(new DefaultModelBindingContext() { BinderModelName = binderModelName, BindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource, BinderType = bindingInfo?.BinderType ?? metadata.BinderType, PropertyFilter = propertyPredicateProvider?.PropertyFilter, // We only support fallback to empty prefix in cases where the model name is inferred from // the parameter or property being bound. FallbackToEmptyPrefix = binderModelName == null, // Because this is the top-level context, FieldName and ModelName should be the same. FieldName = binderModelName ?? modelName, ModelName = binderModelName ?? modelName, IsTopLevelObject = true, ModelMetadata = metadata, ModelState = operationBindingContext.ActionContext.ModelState, OperationBindingContext = operationBindingContext, ValueProvider = operationBindingContext.ValueProvider, ValidationState = new ValidationStateDictionary(), }); }
private static DefaultModelBindingContext GetBindingContext( Type modelType, IEnumerable <IInputFormatter> inputFormatters = null, HttpContext httpContext = null, IModelMetadataProvider metadataProvider = null) { if (httpContext == null) { httpContext = new DefaultHttpContext(); } if (inputFormatters == null) { inputFormatters = Enumerable.Empty <IInputFormatter>(); } if (metadataProvider == null) { metadataProvider = new EmptyModelMetadataProvider(); } var operationBindingContext = new OperationBindingContext { ActionContext = new ActionContext() { HttpContext = httpContext, }, InputFormatters = inputFormatters.ToList(), ModelBinder = new BodyModelBinder(new TestHttpRequestStreamReaderFactory()), MetadataProvider = metadataProvider, }; var bindingContext = new DefaultModelBindingContext { FieldName = "someField", IsTopLevelObject = true, ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelName = "someName", ValueProvider = Mock.Of <IValueProvider>(), ModelState = new ModelStateDictionary(), OperationBindingContext = operationBindingContext, BindingSource = BindingSource.Body, }; return(bindingContext); }
public void CreateBindingContext_FiltersValueProviders_ForValueProviderSource() { // Arrange var metadataProvider = new TestModelMetadataProvider(); var original = CreateDefaultValueProvider(); var operationBindingContext = new OperationBindingContext() { ActionContext = new ActionContext(), ValueProvider = original, }; // Act var context = DefaultModelBindingContext.CreateBindingContext( operationBindingContext, metadataProvider.GetMetadataForType(typeof(object)), new BindingInfo() { BindingSource = BindingSource.Query }, "model"); // Assert Assert.Collection( Assert.IsType<CompositeValueProvider>(context.ValueProvider), vp => Assert.Same(original[1], vp)); }
/// <summary> /// Updates the specified <paramref name="model"/> instance using the specified <paramref name="modelBinder"/> /// and the specified <paramref name="valueProvider"/> and executes validation using the specified /// <paramref name="validatorProvider"/>. /// </summary> /// <param name="model">The model instance to update and validate.</param> /// <param name="modelType">The type of model instance to update and validate.</param> /// <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="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> /// <param name="inputFormatters"> /// The set of <see cref="IInputFormatter"/> instances for deserializing the body. /// </param> /// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the /// bound values.</param> /// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/> used for executing validation /// on the model instance.</param> /// <param name="predicate">A predicate which can be used to /// 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 async Task <bool> TryUpdateModelAsync( object model, Type modelType, string prefix, ActionContext actionContext, IModelMetadataProvider metadataProvider, IModelBinder modelBinder, IValueProvider valueProvider, IList <IInputFormatter> inputFormatters, IObjectModelValidator objectModelValidator, IModelValidatorProvider validatorProvider, Func <ModelBindingContext, string, bool> predicate) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (modelType == null) { throw new ArgumentNullException(nameof(modelType)); } if (prefix == null) { throw new ArgumentNullException(nameof(prefix)); } if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (metadataProvider == null) { throw new ArgumentNullException(nameof(metadataProvider)); } if (modelBinder == null) { throw new ArgumentNullException(nameof(modelBinder)); } if (valueProvider == null) { throw new ArgumentNullException(nameof(valueProvider)); } if (inputFormatters == null) { throw new ArgumentNullException(nameof(inputFormatters)); } if (objectModelValidator == null) { throw new ArgumentNullException(nameof(objectModelValidator)); } if (validatorProvider == null) { throw new ArgumentNullException(nameof(validatorProvider)); } if (predicate == null) { throw new ArgumentNullException(nameof(predicate)); } if (!modelType.IsAssignableFrom(model.GetType())) { var message = Resources.FormatModelType_WrongType( model.GetType().FullName, modelType.FullName); throw new ArgumentException(message, nameof(modelType)); } var modelMetadata = metadataProvider.GetMetadataForType(modelType); var modelState = actionContext.ModelState; var operationBindingContext = new OperationBindingContext { InputFormatters = inputFormatters, ModelBinder = modelBinder, ValidatorProvider = validatorProvider, MetadataProvider = metadataProvider, ActionContext = actionContext, ValueProvider = valueProvider, }; var modelBindingContext = DefaultModelBindingContext.CreateBindingContext( operationBindingContext, modelMetadata, bindingInfo: null, modelName: prefix ?? string.Empty); modelBindingContext.Model = model; modelBindingContext.PropertyFilter = predicate; await modelBinder.BindModelAsync(modelBindingContext); var modelBindingResult = modelBindingContext.Result; if (modelBindingResult != null && modelBindingResult.Value.IsModelSet) { objectModelValidator.Validate( operationBindingContext.ActionContext, operationBindingContext.ValidatorProvider, modelBindingContext.ValidationState, modelBindingResult.Value.Key, modelBindingResult.Value.Model); return(modelState.IsValid); } return(false); }
public void EnterNestedScope_FiltersValueProviders_ForValueProviderSource() { // Arrange var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty(typeof(string), nameof(string.Length)) .BindingDetails(b => b.BindingSource = BindingSource.Query); var original = CreateDefaultValueProvider(); var operationBindingContext = new OperationBindingContext() { ActionContext = new ActionContext(), ValueProvider = original, }; var context = DefaultModelBindingContext.CreateBindingContext( operationBindingContext, metadataProvider.GetMetadataForType(typeof(string)), new BindingInfo(), "model"); var propertyMetadata = metadataProvider.GetMetadataForProperty(typeof(string), nameof(string.Length)); // Act context.EnterNestedScope(propertyMetadata, "Length", "Length", model: null); // Assert Assert.Collection( Assert.IsType<CompositeValueProvider>(context.ValueProvider), vp => Assert.Same(original[1], vp)); }
/// <summary> /// Updates the specified <paramref name="model"/> instance using the specified <paramref name="modelBinderFactory"/> /// and the specified <paramref name="valueProvider"/> and executes validation using the specified /// <paramref name="validatorProvider"/>. /// </summary> /// <param name="model">The model instance to update and validate.</param> /// <param name="modelType">The type of model instance to update and validate.</param> /// <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="metadataProvider">The provider used for reading metadata for the model type.</param> /// <param name="modelBinderFactory">The <see cref="IModelBinderFactory"/> used for binding.</param> /// <param name="valueProvider">The <see cref="IValueProvider"/> used for looking up values.</param> /// <param name="inputFormatters"> /// The set of <see cref="IInputFormatter"/> instances for deserializing the body. /// </param> /// <param name="objectModelValidator">The <see cref="IObjectModelValidator"/> used for validating the /// bound values.</param> /// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/> used for executing validation /// on the model instance.</param> /// <param name="propertyFilter">A predicate which can be used to /// 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 async Task <bool> TryUpdateModelAsync( object model, Type modelType, string prefix, ActionContext actionContext, IModelMetadataProvider metadataProvider, IModelBinderFactory modelBinderFactory, IValueProvider valueProvider, IList <IInputFormatter> inputFormatters, IObjectModelValidator objectModelValidator, IModelValidatorProvider validatorProvider, Func <ModelMetadata, bool> propertyFilter) { if (model == null) { throw new ArgumentNullException(nameof(model)); } if (modelType == null) { throw new ArgumentNullException(nameof(modelType)); } if (prefix == null) { throw new ArgumentNullException(nameof(prefix)); } if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (metadataProvider == null) { throw new ArgumentNullException(nameof(metadataProvider)); } if (modelBinderFactory == null) { throw new ArgumentNullException(nameof(modelBinderFactory)); } if (valueProvider == null) { throw new ArgumentNullException(nameof(valueProvider)); } if (inputFormatters == null) { throw new ArgumentNullException(nameof(inputFormatters)); } if (objectModelValidator == null) { throw new ArgumentNullException(nameof(objectModelValidator)); } if (validatorProvider == null) { throw new ArgumentNullException(nameof(validatorProvider)); } if (propertyFilter == null) { throw new ArgumentNullException(nameof(propertyFilter)); } if (!modelType.IsAssignableFrom(model.GetType())) { var message = Resources.FormatModelType_WrongType( model.GetType().FullName, modelType.FullName); throw new ArgumentException(message, nameof(modelType)); } var modelMetadata = metadataProvider.GetMetadataForType(modelType); var modelState = actionContext.ModelState; var operationBindingContext = new OperationBindingContext { InputFormatters = inputFormatters, ValidatorProvider = validatorProvider, MetadataProvider = metadataProvider, ActionContext = actionContext, ValueProvider = valueProvider, }; var modelBindingContext = DefaultModelBindingContext.CreateBindingContext( operationBindingContext, modelMetadata, bindingInfo: null, modelName: prefix ?? string.Empty); modelBindingContext.Model = model; modelBindingContext.PropertyFilter = propertyFilter; var factoryContext = new ModelBinderFactoryContext() { Metadata = modelMetadata, BindingInfo = new BindingInfo() { BinderModelName = modelMetadata.BinderModelName, BinderType = modelMetadata.BinderType, BindingSource = modelMetadata.BindingSource, PropertyFilterProvider = modelMetadata.PropertyFilterProvider, }, // We're using the model metadata as the cache token here so that TryUpdateModelAsync calls // for the same model type can share a binder. This won't overlap with normal model binding // operations because they use the ParameterDescriptor for the token. CacheToken = modelMetadata, }; var binder = modelBinderFactory.CreateBinder(factoryContext); await binder.BindModelAsync(modelBindingContext); var modelBindingResult = modelBindingContext.Result; if (modelBindingResult != null && modelBindingResult.Value.IsModelSet) { objectModelValidator.Validate( operationBindingContext.ActionContext, operationBindingContext.ValidatorProvider, modelBindingContext.ValidationState, modelBindingResult.Value.Key, modelBindingResult.Value.Model); return(modelState.IsValid); } return(false); }