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)); }
private static DefaultModelBindingContext GetModelBindingContext( IValueProvider valueProvider, bool isReadOnly = false) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider .ForProperty <ModelWithIListProperty>(nameof(ModelWithIListProperty.ListProperty)) .BindingDetails(bd => bd.IsReadOnly = isReadOnly); var metadata = metadataProvider.GetMetadataForProperty( typeof(ModelWithIListProperty), nameof(ModelWithIListProperty.ListProperty)); var bindingContext = new DefaultModelBindingContext { ModelMetadata = metadata, ModelName = "someName", ModelState = new ModelStateDictionary(), ValueProvider = valueProvider, OperationBindingContext = new OperationBindingContext { ModelBinder = CreateIntBinder(), MetadataProvider = metadataProvider }, ValidationState = new ValidationStateDictionary(), FieldName = "testfieldname", }; return(bindingContext); }
private static (DefaultModelBindingContext, IModelBinder) GetBinderAndContext( Type modelType, bool suppressBindingUndefinedValueToEnumType, object valueProviderValue) { var binderProviderContext = new TestModelBinderProviderContext(modelType); var modelName = "theModelName"; var bindingContext = new DefaultModelBindingContext { ModelMetadata = binderProviderContext.Metadata, ModelName = modelName, ModelState = new ModelStateDictionary(), ValueProvider = new SimpleValueProvider() { { modelName, valueProviderValue } } }; var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions { SuppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType }); var binder = binderProvider.GetBinder(binderProviderContext); return(bindingContext, binder); }
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)); }
public void BindAttribute_ProviderType_Cached() { // Arrange var bind = new BindAttribute(typeof(TestProvider)); var context = new DefaultModelBindingContext(); context.OperationBindingContext = new OperationBindingContext() { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext(), }, }; var services = new Mock <IServiceProvider>(MockBehavior.Strict); context.OperationBindingContext.HttpContext.RequestServices = services.Object; // Act var predicate = bind.PropertyFilter; // Assert Assert.True(predicate(context, "UserName")); Assert.True(predicate(context, "UserName")); }
public void ModelTypeAreFedFromModelMetadata() { // Act var bindingContext = new DefaultModelBindingContext { ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)) }; // Assert Assert.Equal(typeof(int), bindingContext.ModelType); }
public void EnterNestedScope_CopiesProperties() { // Arrange var bindingContext = new DefaultModelBindingContext { Model = new object(), ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelName = "theName", OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider(), ModelState = new ModelStateDictionary(), }; 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 originalBinderModelName = bindingContext.BinderModelName; var originalBinderType = bindingContext.BinderType; var originalBindingSource = bindingContext.BindingSource; var originalModelState = bindingContext.ModelState; var originalOperationBindingContext = bindingContext.OperationBindingContext; var originalValueProvider = bindingContext.ValueProvider; var disposable = bindingContext.EnterNestedScope( modelMetadata: newModelMetadata, fieldName: "fieldName", modelName: "modelprefix.fieldName", model: null); // Assert Assert.Same(newModelMetadata.BinderModelName, bindingContext.BinderModelName); Assert.Same(newModelMetadata.BinderType, bindingContext.BinderType); Assert.Same(newModelMetadata.BindingSource, bindingContext.BindingSource); Assert.False(bindingContext.FallbackToEmptyPrefix); Assert.Equal("fieldName", bindingContext.FieldName); Assert.False(bindingContext.IsTopLevelObject); Assert.Null(bindingContext.Model); Assert.Same(newModelMetadata, bindingContext.ModelMetadata); Assert.Equal("modelprefix.fieldName", bindingContext.ModelName); Assert.Same(originalModelState, bindingContext.ModelState); Assert.Same(originalOperationBindingContext, bindingContext.OperationBindingContext); Assert.Same(originalValueProvider, bindingContext.ValueProvider); disposable.Dispose(); }
public void BindAttribute_Include(string property, bool isIncluded) { // Arrange var bind = new BindAttribute(new string[] { "UserName", "FirstName", "LastName, MiddleName, ,foo,bar " }); var context = new DefaultModelBindingContext(); // Act var predicate = bind.PropertyFilter; // Assert Assert.Equal(isIncluded, predicate(context, property)); }
public void EnterNestedScope_CopiesProperties() { // Arrange var bindingContext = new DefaultModelBindingContext { Model = new object(), ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)), ModelName = "theName", OperationBindingContext = new OperationBindingContext(), ValueProvider = new SimpleValueProvider(), ModelState = new ModelStateDictionary(), }; 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 originalBinderModelName = bindingContext.BinderModelName; var originalBindingSource = bindingContext.BindingSource; var originalModelState = bindingContext.ModelState; var originalOperationBindingContext = bindingContext.OperationBindingContext; var originalValueProvider = bindingContext.ValueProvider; var disposable = bindingContext.EnterNestedScope( modelMetadata: newModelMetadata, fieldName: "fieldName", modelName: "modelprefix.fieldName", model: null); // Assert Assert.Same(newModelMetadata.BinderModelName, bindingContext.BinderModelName); Assert.Same(newModelMetadata.BindingSource, bindingContext.BindingSource); Assert.Equal("fieldName", bindingContext.FieldName); Assert.False(bindingContext.IsTopLevelObject); Assert.Null(bindingContext.Model); Assert.Same(newModelMetadata, bindingContext.ModelMetadata); Assert.Equal("modelprefix.fieldName", bindingContext.ModelName); Assert.Same(originalModelState, bindingContext.ModelState); Assert.Same(originalOperationBindingContext, bindingContext.OperationBindingContext); Assert.Same(originalValueProvider, bindingContext.ValueProvider); disposable.Dispose(); }
private static DefaultModelBindingContext CreateContext() { var modelBindingContext = new DefaultModelBindingContext() { OperationBindingContext = new OperationBindingContext() { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext(), }, MetadataProvider = new TestModelMetadataProvider(), } }; return(modelBindingContext); }
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 BindAttribute_Include(string property, bool isIncluded) { // Arrange var bind = new BindAttribute(new string[] { "UserName", "FirstName", "LastName, MiddleName, ,foo,bar " }); var context = new DefaultModelBindingContext(); var identity = ModelMetadataIdentity.ForProperty(typeof(int), property, typeof(string)); context.ModelMetadata = new Mock <ModelMetadata>(identity).Object; // Act var propertyFilter = bind.PropertyFilter; // Assert Assert.Equal(isIncluded, propertyFilter(context.ModelMetadata)); }
private static DefaultModelBindingContext GetBindingContext(Type modelType) { var metadataProvider = new EmptyModelMetadataProvider(); DefaultModelBindingContext bindingContext = new DefaultModelBindingContext { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext(), }, ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelName = "someName", ValidationState = new ValidationStateDictionary(), }; bindingContext.HttpContext.Request.Method = "GET"; return bindingContext; }
private static DefaultModelBindingContext GetBindingContext(Type modelType, HttpContext httpContext) { var metadataProvider = new EmptyModelMetadataProvider(); var bindingContext = new DefaultModelBindingContext { ModelMetadata = metadataProvider.GetMetadataForType(modelType), ModelName = "file", OperationBindingContext = new OperationBindingContext { ActionContext = new ActionContext() { HttpContext = httpContext, }, ModelBinder = new FormCollectionModelBinder(), MetadataProvider = metadataProvider, }, ValidationState = new ValidationStateDictionary(), }; return(bindingContext); }
private static DefaultModelBindingContext GetBindingContext(Type modelType) { var metadataProvider = new TestModelMetadataProvider(); metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Services); var modelMetadata = metadataProvider.GetMetadataForType(modelType); var services = new ServiceCollection(); services.AddSingleton <IService>(new Service()); var bindingContext = new DefaultModelBindingContext { ModelMetadata = modelMetadata, ModelName = "modelName", FieldName = "modelName", ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext() { RequestServices = services.BuildServiceProvider(), } }, ModelBinder = new HeaderModelBinder(), MetadataProvider = metadataProvider, }, BinderModelName = modelMetadata.BinderModelName, BindingSource = modelMetadata.BindingSource, ValidationState = new ValidationStateDictionary(), }; return(bindingContext); }
private static DefaultModelBindingContext GetBindingContext( IModelMetadataProvider metadataProvider, ModelMetadata metadata, HttpContext httpContext) { var bindingContext = new DefaultModelBindingContext { ModelMetadata = metadata, ModelName = "file", ModelState = new ModelStateDictionary(), OperationBindingContext = new OperationBindingContext { ActionContext = new ActionContext() { HttpContext = httpContext, }, ModelBinder = new FormFileModelBinder(), MetadataProvider = metadataProvider, }, ValidationState = new ValidationStateDictionary(), }; return(bindingContext); }
public void BindAttribute_ProviderType(string property, bool isIncluded) { // Arrange var bind = new BindAttribute(typeof(TestProvider)); var context = new DefaultModelBindingContext(); context.OperationBindingContext = new OperationBindingContext() { ActionContext = new ActionContext() { HttpContext = new DefaultHttpContext(), }, }; var services = new Mock <IServiceProvider>(); context.OperationBindingContext.HttpContext.RequestServices = services.Object; // Act var predicate = bind.PropertyFilter; // Assert Assert.Equal(isIncluded, predicate(context, property)); }
/// <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); }
/// <summary> /// Binds a model specified by <paramref name="parameter"/> using <paramref name="value"/> as the initial value. /// </summary> /// <param name="actionContext">The <see cref="ActionContext"/>.</param> /// <param name="modelBinder">The <see cref="IModelBinder"/>.</param> /// <param name="valueProvider">The <see cref="IValueProvider"/>.</param> /// <param name="parameter">The <see cref="ParameterDescriptor"/></param> /// <param name="metadata">The <see cref="ModelMetadata"/>.</param> /// <param name="value">The initial model value.</param> /// <returns>The result of model binding.</returns> public virtual async Task <ModelBindingResult> BindModelAsync( ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, object value) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (modelBinder == null) { throw new ArgumentNullException(nameof(modelBinder)); } if (valueProvider == null) { throw new ArgumentNullException(nameof(valueProvider)); } if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (parameter.BindingInfo?.RequestPredicate?.Invoke(actionContext) == false) { return(ModelBindingResult.Failed()); } var modelBindingContext = DefaultModelBindingContext.CreateBindingContext( actionContext, valueProvider, metadata, parameter.BindingInfo, parameter.Name); modelBindingContext.Model = value; var parameterModelName = parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName; if (parameterModelName != null) { // The name was set explicitly, always use that as the prefix. modelBindingContext.ModelName = parameterModelName; } else if (modelBindingContext.ValueProvider.ContainsPrefix(parameter.Name)) { // We have a match for the parameter name, use that as that prefix. modelBindingContext.ModelName = parameter.Name; } else { // No match, fallback to empty string as the prefix. modelBindingContext.ModelName = string.Empty; } await modelBinder.BindModelAsync(modelBindingContext); var modelBindingResult = modelBindingContext.Result; if (modelBindingResult.IsModelSet) { _validator.Validate( actionContext, modelBindingContext.ValidationState, modelBindingContext.ModelName, modelBindingResult.Model); } return(modelBindingResult); }
/// <summary> /// Binds a model specified by <paramref name="parameter"/> using <paramref name="value"/> as the initial value. /// </summary> /// <param name="actionContext">The <see cref="ActionContext"/>.</param> /// <param name="modelBinder">The <see cref="IModelBinder"/>.</param> /// <param name="valueProvider">The <see cref="IValueProvider"/>.</param> /// <param name="parameter">The <see cref="ParameterDescriptor"/></param> /// <param name="metadata">The <see cref="ModelMetadata"/>.</param> /// <param name="value">The initial model value.</param> /// <returns>The result of model binding.</returns> public virtual async Task <ModelBindingResult> BindModelAsync( ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, object value) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (modelBinder == null) { throw new ArgumentNullException(nameof(modelBinder)); } if (valueProvider == null) { throw new ArgumentNullException(nameof(valueProvider)); } if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (parameter.BindingInfo?.RequestPredicate?.Invoke(actionContext) == false) { return(ModelBindingResult.Failed()); } var modelBindingContext = DefaultModelBindingContext.CreateBindingContext( actionContext, valueProvider, metadata, parameter.BindingInfo, parameter.Name); modelBindingContext.Model = value; var parameterModelName = parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName; if (parameterModelName != null) { // The name was set explicitly, always use that as the prefix. modelBindingContext.ModelName = parameterModelName; } else if (modelBindingContext.ValueProvider.ContainsPrefix(parameter.Name)) { // We have a match for the parameter name, use that as that prefix. modelBindingContext.ModelName = parameter.Name; } else { // No match, fallback to empty string as the prefix. modelBindingContext.ModelName = string.Empty; } await modelBinder.BindModelAsync(modelBindingContext); var modelBindingResult = modelBindingContext.Result; if (_validatorForBackCompatOnly != null) { // Since we don't have access to an IModelValidatorProvider, fall back // on back-compatibility logic. In this scenario, top-level validation // attributes will be ignored like they were historically. if (modelBindingResult.IsModelSet) { _validatorForBackCompatOnly.Validate( actionContext, modelBindingContext.ValidationState, modelBindingContext.ModelName, modelBindingResult.Model); } } else { EnforceBindRequiredAndValidate( actionContext, metadata, modelBindingContext, modelBindingResult); } return(modelBindingResult); }
public void ModelTypeAreFedFromModelMetadata() { // Act var bindingContext = new DefaultModelBindingContext { ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(int)) }; // Assert Assert.Equal(typeof(int), bindingContext.ModelType); }
public static async Task <bool> TryUpdateModelAsync( object model, Type modelType, string prefix, ActionContext actionContext, IModelMetadataProvider metadataProvider, IModelBinderFactory modelBinderFactory, IValueProvider valueProvider, IObjectModelValidator objectModelValidator, 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 (objectModelValidator == null) { throw new ArgumentNullException(nameof(objectModelValidator)); } 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); if (modelMetadata.BoundConstructor != null) { throw new NotSupportedException(Resources.FormatTryUpdateModel_RecordTypeNotSupported(nameof(TryUpdateModelAsync), modelType)); } var modelState = actionContext.ModelState; var modelBindingContext = DefaultModelBindingContext.CreateBindingContext( actionContext, valueProvider, modelMetadata, bindingInfo: null, modelName: prefix); 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.IsModelSet) { objectModelValidator.Validate( actionContext, modelBindingContext.ValidationState, modelBindingContext.ModelName, modelBindingResult.Model); return(modelState.IsValid); } return(false); }
/// <summary> /// Creates a new <see cref="DefaultModelBindingContext"/> for top-level model binding operation. /// </summary> /// <param name="actionContext"> /// The <see cref="ActionContext"/> associated with the binding operation. /// </param> /// <param name="valueProvider">The <see cref="IValueProvider"/> to use for binding.</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( ActionContext actionContext, IValueProvider valueProvider, ModelMetadata metadata, BindingInfo bindingInfo, string modelName) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (valueProvider == null) { throw new ArgumentNullException(nameof(valueProvider)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (modelName == null) { throw new ArgumentNullException(nameof(modelName)); } var binderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName; var bindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource; var propertyFilterProvider = bindingInfo?.PropertyFilterProvider ?? metadata.PropertyFilterProvider; var bindingContext = new DefaultModelBindingContext() { ActionContext = actionContext, BinderModelName = binderModelName, BindingSource = bindingSource, PropertyFilter = propertyFilterProvider?.PropertyFilter, ValidationState = new ValidationStateDictionary(), // Because this is the top-level context, FieldName and ModelName should be the same. FieldName = binderModelName ?? modelName, ModelName = binderModelName ?? modelName, OriginalModelName = binderModelName ?? modelName, IsTopLevelObject = true, ModelMetadata = metadata, ModelState = actionContext.ModelState, OriginalValueProvider = valueProvider, ValueProvider = FilterValueProvider(valueProvider, bindingSource), }; // mvcOptions may be null when this method is called in test scenarios. var mvcOptions = actionContext.HttpContext.RequestServices?.GetService <IOptions <MvcOptions> >(); if (mvcOptions != null) { bindingContext.MaxModelBindingRecursionDepth = mvcOptions.Value.MaxModelBindingRecursionDepth; } return(bindingContext); }
public void ModelMetadataProvider_UsesPropertyFilterProviderOnType() { // Arrange var type = typeof(User); var provider = CreateProvider(); var context = new DefaultModelBindingContext(); var expected = new[] { "IsAdmin", "UserName" }; // Act var metadata = provider.GetMetadataForType(type); // Assert var propertyFilter = metadata.PropertyFilterProvider.PropertyFilter; var matched = new HashSet<string>(); foreach (var property in metadata.Properties) { if (propertyFilter(property)) { matched.Add(property.PropertyName); } } Assert.Equal<string>(expected, matched); }
/// <summary> /// Binds a model specified by <paramref name="parameter"/> using <paramref name="value"/> as the initial value. /// </summary> /// <param name="actionContext">The <see cref="ActionContext"/>.</param> /// <param name="modelBinder">The <see cref="IModelBinder"/>.</param> /// <param name="valueProvider">The <see cref="IValueProvider"/>.</param> /// <param name="parameter">The <see cref="ParameterDescriptor"/></param> /// <param name="metadata">The <see cref="ModelMetadata"/>.</param> /// <param name="value">The initial model value.</param> /// <returns>The result of model binding.</returns> public virtual async Task <ModelBindingResult> BindModelAsync( ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, object value) { if (actionContext == null) { throw new ArgumentNullException(nameof(actionContext)); } if (modelBinder == null) { throw new ArgumentNullException(nameof(modelBinder)); } if (valueProvider == null) { throw new ArgumentNullException(nameof(valueProvider)); } if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (parameter.BindingInfo?.RequestPredicate?.Invoke(actionContext) == false) { return(ModelBindingResult.Failed()); } var modelBindingContext = DefaultModelBindingContext.CreateBindingContext( actionContext, valueProvider, metadata, parameter.BindingInfo, parameter.Name); modelBindingContext.Model = value; Logger.AttemptingToBindParameterOrProperty(parameter, modelBindingContext); var parameterModelName = parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName; if (parameterModelName != null) { // The name was set explicitly, always use that as the prefix. modelBindingContext.ModelName = parameterModelName; } else if (modelBindingContext.ValueProvider.ContainsPrefix(parameter.Name)) { // We have a match for the parameter name, use that as that prefix. modelBindingContext.ModelName = parameter.Name; } else { // No match, fallback to empty string as the prefix. modelBindingContext.ModelName = string.Empty; } await modelBinder.BindModelAsync(modelBindingContext); Logger.DoneAttemptingToBindParameterOrProperty(parameter, modelBindingContext); var modelBindingResult = modelBindingContext.Result; if (_mvcOptions.AllowValidatingTopLevelNodes && _objectModelValidator is ObjectModelValidator baseObjectValidator) { Logger.AttemptingToValidateParameterOrProperty(parameter, modelBindingContext); EnforceBindRequiredAndValidate( baseObjectValidator, actionContext, parameter, metadata, modelBindingContext, modelBindingResult); Logger.DoneAttemptingToValidateParameterOrProperty(parameter, modelBindingContext); } else { // For legacy implementations (which directly implemented IObjectModelValidator), fall back to the // back-compatibility logic. In this scenario, top-level validation attributes will be ignored like // they were historically. if (modelBindingResult.IsModelSet) { _objectModelValidator.Validate( actionContext, modelBindingContext.ValidationState, modelBindingContext.ModelName, modelBindingResult.Model); } } return(modelBindingResult); }