コード例 #1
0
        public void SetProperty_PropertyIsSettable_CallsSetter()
        {
            // Arrange
            var model          = new Person();
            var bindingContext = CreateContext(GetMetadataForObject(model));

            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult         = new ComplexModelDtoResult(new DateTime(2001, 1, 1), validationNode);
            var requiredValidator = bindingContext.ValidatorProviders
                                    .SelectMany(v => v.GetValidators(propertyMetadata))
                                    .Where(v => v.IsRequired)
                                    .FirstOrDefault();
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            validationNode.Validate(validationContext);
            Assert.Equal(true, bindingContext.ModelState.IsValid);
            Assert.Equal(new DateTime(2001, 1, 1), model.DateOfBirth);
        }
コード例 #2
0
        public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            if(bindingContext.ModelType != typeof(Currency))
            {
                return ModelBindingResult.NoResultAsync;
            }

            var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if(valueProviderResult == ValueProviderResult.None)
            {
                return ModelBindingResult.FailedAsync(bindingContext.ModelName);
            }

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            var value = valueProviderResult.FirstValue;
            if(string.IsNullOrEmpty(value))
            {
                return ModelBindingResult.FailedAsync(bindingContext.ModelName);
            }

            var model = (Currency)value;
            if(model == null)
            {
                return ModelBindingResult.FailedAsync(bindingContext.ModelName);
            }

            var validationNode = new ModelValidationNode(
                bindingContext.ModelName,
                bindingContext.ModelMetadata,
                model
            );

            return ModelBindingResult.SuccessAsync(bindingContext.ModelName, model, validationNode);
        }
コード例 #3
0
        /// <inheritdoc />
        public async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(IFormFile))
            {
                var postedFiles = await GetFormFilesAsync(bindingContext);
                var value = postedFiles.FirstOrDefault();
                var validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);
                return new ModelBindingResult(
                    value,
                    bindingContext.ModelName,
                    isModelSet: value != null,
                    validationNode: validationNode);
            }
            else if (typeof(IEnumerable<IFormFile>).GetTypeInfo().IsAssignableFrom(
                    bindingContext.ModelType.GetTypeInfo()))
            {
                var postedFiles = await GetFormFilesAsync(bindingContext);
                var value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles);
                var validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);
                return new ModelBindingResult(
                    value,
                    bindingContext.ModelName,
                    isModelSet: value != null,
                    validationNode: validationNode);
            }

            return null;
        }
コード例 #4
0
        private void ValidateThis(ModelValidationContext validationContext, ModelValidationNode parentNode)
        {
            var modelState = validationContext.ModelState;

            if (modelState.GetFieldValidationState(ModelStateKey) == ModelValidationState.Invalid)
            {
                // If any item in the key's subtree has been identified as invalid, short-circuit
                return;
            }

            // If the Model at the current node is null and there is no parent, we cannot validate, and the
            // DataAnnotationsModelValidator will throw. So we intercept here to provide a catch-all value-required
            // validation error
            if (parentNode == null && ModelMetadata.Model == null)
            {
                modelState.TryAddModelError(ModelStateKey, Resources.Validation_ValueNotFound);
                return;
            }

            var container  = TryConvertContainerToMetadataType(parentNode);
            var validators = GetValidators(validationContext, ModelMetadata).ToArray();

            for (var i = 0; i < validators.Length; i++)
            {
                var validator = validators[i];
                foreach (var validationResult in validator.Validate(validationContext))
                {
                    var currentModelStateKey = ModelBindingHelper.CreatePropertyModelName(ModelStateKey,
                                                                                          validationResult.MemberName);
                    modelState.TryAddModelError(currentModelStateKey, validationResult.Message);
                }
            }
        }
コード例 #5
0
ファイル: FormFileModelBinder.cs プロジェクト: notami18/Mvc
        /// <inheritdoc />
        public async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            object value;
            if (bindingContext.ModelType == typeof(IFormFile))
            {
                var postedFiles = await GetFormFilesAsync(bindingContext);
                value = postedFiles.FirstOrDefault();
            }
            else if (typeof(IEnumerable<IFormFile>).IsAssignableFrom(bindingContext.ModelType))
            {
                var postedFiles = await GetFormFilesAsync(bindingContext);
                value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles);
            }
            else
            {
                // This binder does not support the requested type.
                return null;
            }

            ModelValidationNode validationNode = null;
            if (value != null)
            {
                validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);

                var valueProviderResult = new ValueProviderResult(rawValue: value);
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            }

            return new ModelBindingResult(
                value,
                bindingContext.ModelName,
                isModelSet: value != null,
                validationNode: validationNode);
        }
コード例 #6
0
        public void Validate([NotNull] ModelValidationContext validationContext, ModelValidationNode parentNode)
        {
            if (SuppressValidation || !validationContext.ModelState.CanAddErrors)
            {
                // Short circuit if validation does not need to be applied or if we've reached the max number of validation errors.
                return;
            }

            // pre-validation steps
            var validatingEventArgs = new ModelValidatingEventArgs(validationContext, parentNode);

            OnValidating(validatingEventArgs);
            if (validatingEventArgs.Cancel)
            {
                return;
            }

            ValidateChildren(validationContext);
            ValidateThis(validationContext, parentNode);

            // post-validation steps
            var validatedEventArgs = new ModelValidatedEventArgs(validationContext, parentNode);

            OnValidated(validatedEventArgs);

            var modelState = validationContext.ModelState;

            if (modelState.GetFieldValidationState(ModelStateKey) != ModelValidationState.Invalid)
            {
                // If a node or its subtree were not marked invalid, we can consider it valid at this point.
                modelState.MarkFieldValid(ModelStateKey);
            }
        }
コード例 #7
0
ファイル: MutableObjectModelBinder.cs プロジェクト: zt97/Mvc
        /// <inheritdoc />
        public virtual async Task <ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);
            if (!CanBindType(bindingContext.ModelMetadata))
            {
                return(null);
            }

            var mutableObjectBinderContext = new MutableObjectBinderContext()
            {
                ModelBindingContext = bindingContext,
                PropertyMetadata    = GetMetadataForProperties(bindingContext).ToArray(),
            };

            if (!(await CanCreateModel(mutableObjectBinderContext)))
            {
                return(null);
            }

            EnsureModel(bindingContext);
            var result = await CreateAndPopulateDto(bindingContext, mutableObjectBinderContext.PropertyMetadata);

            var validationNode = new ModelValidationNode(
                bindingContext.ModelName,
                bindingContext.ModelMetadata,
                bindingContext.Model);

            // post-processing, e.g. property setters and hooking up validation
            ProcessDto(bindingContext, (ComplexModelDto)result.Model, validationNode);
            return(new ModelBindingResult(
                       bindingContext.Model,
                       bindingContext.ModelName,
                       isModelSet: true,
                       validationNode: validationNode));
        }
コード例 #8
0
        // Used when the ValueProvider contains the collection to be bound as a single element, e.g. the raw value
        // is [ "1", "2" ] and needs to be converted to an int[].
        internal async Task <CollectionResult> BindSimpleCollection(
            ModelBindingContext bindingContext,
            object rawValue,
            CultureInfo culture)
        {
            if (rawValue == null)
            {
                return(null); // nothing to do
            }

            var boundCollection = new List <TElement>();

            var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
            var elementMetadata  = metadataProvider.GetMetadataForType(typeof(TElement));

            var validationNode = new ModelValidationNode(
                bindingContext.ModelName,
                bindingContext.ModelMetadata,
                boundCollection);
            var rawValueArray = RawValueToObjectArray(rawValue);

            foreach (var rawValueElement in rawValueArray)
            {
                var innerBindingContext = ModelBindingContext.GetChildModelBindingContext(
                    bindingContext,
                    bindingContext.ModelName,
                    elementMetadata);
                innerBindingContext.ValueProvider = new CompositeValueProvider
                {
                    // our temporary provider goes at the front of the list
                    new ElementalValueProvider(bindingContext.ModelName, rawValueElement, culture),
                    bindingContext.ValueProvider
                };

                object boundValue = null;
                var    result     =
                    await bindingContext.OperationBindingContext.ModelBinder.BindModelAsync(innerBindingContext);

                if (result != null && result.IsModelSet)
                {
                    boundValue = result.Model;
                    if (result.ValidationNode != null)
                    {
                        validationNode.ChildNodes.Add(result.ValidationNode);
                    }
                }
                boundCollection.Add(ModelBindingHelper.CastOrDefault <TElement>(boundValue));
            }

            return(new CollectionResult
            {
                ValidationNode = validationNode,
                Model = boundCollection
            });
        }
コード例 #9
0
        /// <inheritdoc />
        protected async override Task <ModelBindingResult> BindModelCoreAsync(
            [NotNull] ModelBindingContext bindingContext)
        {
            var httpContext = bindingContext.OperationBindingContext.HttpContext;
            var formatters  = bindingContext.OperationBindingContext.InputFormatters;

            var formatterContext = new InputFormatterContext(
                httpContext,
                bindingContext.ModelState,
                bindingContext.ModelType);
            var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext));

            if (formatter == null)
            {
                var unsupportedContentType = Resources.FormatUnsupportedContentType(
                    bindingContext.OperationBindingContext.HttpContext.Request.ContentType);
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType);

                // This model binder is the only handler for the Body binding source.
                // Always tell the model binding system to skip other model binders i.e. return non-null.
                return(new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false));
            }

            try
            {
                var model = await formatter.ReadAsync(formatterContext);

                var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;

                // For compatibility with MVC 5.0 for top level object we want to consider an empty key instead of
                // the parameter name/a custom name. In all other cases (like when binding body to a property) we
                // consider the entire ModelName as a prefix.
                var modelBindingKey = isTopLevelObject ? string.Empty : bindingContext.ModelName;

                var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model)
                {
                    ValidateAllProperties = true
                };

                return(new ModelBindingResult(
                           model,
                           key: modelBindingKey,
                           isModelSet: true,
                           validationNode: validationNode));
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);

                // This model binder is the only handler for the Body binding source.
                // Always tell the model binding system to skip other model binders i.e. return non-null.
                return(new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false));
            }
        }
コード例 #10
0
        /// <inheritdoc />
        protected async override Task<ModelBindingResult> BindModelCoreAsync(
            [NotNull] ModelBindingContext bindingContext)
        {
            var httpContext = bindingContext.OperationBindingContext.HttpContext;
            var formatters = bindingContext.OperationBindingContext.InputFormatters;

            var formatterContext = new InputFormatterContext(
                httpContext, 
                bindingContext.ModelState, 
                bindingContext.ModelType);
            var formatter = formatters.FirstOrDefault(f => f.CanRead(formatterContext));

            if (formatter == null)
            {
                var unsupportedContentType = Resources.FormatUnsupportedContentType(
                    bindingContext.OperationBindingContext.HttpContext.Request.ContentType);
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType);

                // This model binder is the only handler for the Body binding source.
                // Always tell the model binding system to skip other model binders i.e. return non-null.
                return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
            }

            try
            {
                var model = await formatter.ReadAsync(formatterContext);

                var isTopLevelObject = bindingContext.ModelMetadata.ContainerType == null;

                // For compatibility with MVC 5.0 for top level object we want to consider an empty key instead of
                // the parameter name/a custom name. In all other cases (like when binding body to a property) we
                // consider the entire ModelName as a prefix.
                var modelBindingKey = isTopLevelObject ? string.Empty : bindingContext.ModelName;

                var validationNode = new ModelValidationNode(modelBindingKey, bindingContext.ModelMetadata, model)
                {
                    ValidateAllProperties = true
                };

                return new ModelBindingResult(
                    model,
                    key: modelBindingKey,
                    isModelSet: true,
                    validationNode: validationNode);
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex);

                // This model binder is the only handler for the Body binding source.
                // Always tell the model binding system to skip other model binders i.e. return non-null.
                return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
            }
        }
コード例 #11
0
ファイル: TypeConverterModelBinder.cs プロジェクト: zt97/Mvc
        public async Task <ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (bindingContext.ModelMetadata.IsComplexType)
            {
                // this type cannot be converted
                return(null);
            }

            var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);

            if (valueProviderResult == null)
            {
                return(null); // no entry
            }

            object newModel;

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            try
            {
                newModel = valueProviderResult.ConvertTo(bindingContext.ModelType);
                ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
                var validationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    newModel);
                var isModelSet = true;

                // When converting newModel a null value may indicate a failed conversion for an otherwise required
                // model (can't set a ValueType to null). This detects if a null model value is acceptable given the
                // current bindingContext. If not, an error is logged.
                if (newModel == null && !AllowsNullValue(bindingContext.ModelType))
                {
                    bindingContext.ModelState.TryAddModelError(
                        bindingContext.ModelName,
                        Resources.FormatCommon_ValueNotValidForProperty(newModel));

                    isModelSet = false;
                }

                return(new ModelBindingResult(newModel, bindingContext.ModelName, isModelSet, validationNode));
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
            }

            // Were able to find a converter for the type but conversion failed.
            // Tell the model binding system to skip other model binders i.e. return non-null.
            return(new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false));
        }
コード例 #12
0
        public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (bindingContext.ModelMetadata.IsComplexType)
            {
                // this type cannot be converted
                return null;
            }

            var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
            if (valueProviderResult == null)
            {
                return null; // no entry
            }

            object newModel;
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            try
            {
                newModel = valueProviderResult.ConvertTo(bindingContext.ModelType);
                ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
                var validationNode = new ModelValidationNode(
                   bindingContext.ModelName,
                   bindingContext.ModelMetadata,
                   newModel);
                var isModelSet = true;

                // When converting newModel a null value may indicate a failed conversion for an otherwise required 
                // model (can't set a ValueType to null). This detects if a null model value is acceptable given the
                // current bindingContext. If not, an error is logged.
                if (newModel == null && !AllowsNullValue(bindingContext.ModelType))
                {
                    bindingContext.ModelState.TryAddModelError(
                        bindingContext.ModelName,
                        Resources.FormatCommon_ValueNotValidForProperty(newModel));

                    isModelSet = false;
                }

                return new ModelBindingResult(newModel, bindingContext.ModelName, isModelSet, validationNode);
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
            }

            // Were able to find a converter for the type but conversion failed.
            // Tell the model binding system to skip other model binders i.e. return non-null.
            return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
        }
コード例 #13
0
        // Internal for testing.
        internal ModelValidationNode ProcessResults(
            ModelBindingContext bindingContext,
            IDictionary <ModelMetadata, ModelBindingResult> results,
            ModelValidationNode validationNode)
        {
            var metadataProvider = bindingContext.OperationBindingContext.MetadataProvider;
            var modelExplorer    =
                metadataProvider.GetModelExplorerForType(bindingContext.ModelType, bindingContext.Model);
            var validationInfo = GetPropertyValidationInfo(bindingContext);

            // Eliminate provided properties from RequiredProperties; leaving just *missing* required properties.
            var boundProperties = results.Where(p => p.Value.IsModelSet).Select(p => p.Key.PropertyName);

            validationInfo.RequiredProperties.ExceptWith(boundProperties);

            foreach (var missingRequiredProperty in validationInfo.RequiredProperties)
            {
                var propertyExplorer = modelExplorer.GetExplorerForProperty(missingRequiredProperty);
                var propertyName     = propertyExplorer.Metadata.BinderModelName ?? missingRequiredProperty;
                var modelStateKey    = ModelNames.CreatePropertyModelName(bindingContext.ModelName, propertyName);

                bindingContext.ModelState.TryAddModelError(
                    modelStateKey,
                    Resources.FormatModelBinding_MissingBindRequiredMember(propertyName));
            }

            // For each property that BindPropertiesAsync() attempted to bind, call the setter, recording
            // exceptions as necessary.
            foreach (var entry in results)
            {
                var result = entry.Value;
                if (result != null)
                {
                    var propertyMetadata = entry.Key;
                    SetProperty(bindingContext, modelExplorer, propertyMetadata, result);

                    var propertyValidationNode = result.ValidationNode;
                    if (propertyValidationNode == null)
                    {
                        // Make sure that irrespective of whether the properties of the model were bound with a value,
                        // create a validation node so that these get validated.
                        propertyValidationNode = new ModelValidationNode(result.Key, entry.Key, result.Model);
                    }

                    validationNode.ChildNodes.Add(propertyValidationNode);
                }
            }

            return(validationNode);
        }
コード例 #14
0
ファイル: ModelValidationNode.cs プロジェクト: gmmateev/Mvc
 public void CombineWith(ModelValidationNode otherNode)
 {
     if (otherNode != null && !otherNode.SuppressValidation)
     {
         Validated  += otherNode.Validated;
         Validating += otherNode.Validating;
         var otherChildNodes = otherNode._childNodes;
         for (var i = 0; i < otherChildNodes.Count; i++)
         {
             var childNode = otherChildNodes[i];
             _childNodes.Add(childNode);
         }
     }
 }
コード例 #15
0
ファイル: ModelValidationNode.cs プロジェクト: Nakro/Mvc
 public void CombineWith(ModelValidationNode otherNode)
 {
     if (otherNode != null && !otherNode.SuppressValidation)
     {
         Validated += otherNode.Validated;
         Validating += otherNode.Validating;
         var otherChildNodes = otherNode._childNodes;
         for (var i = 0; i < otherChildNodes.Count; i++)
         {
             var childNode = otherChildNodes[i];
             _childNodes.Add(childNode);
         }
     }
 }
コード例 #16
0
ファイル: HeaderModelBinder.cs プロジェクト: zt97/Mvc
        /// <inheritdoc />
        protected override Task <ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext)
        {
            var request       = bindingContext.OperationBindingContext.HttpContext.Request;
            var modelMetadata = bindingContext.ModelMetadata;

            // Property name can be null if the model metadata represents a type (rather than a property or parameter).
            var    headerName = bindingContext.BinderModelName ?? modelMetadata.PropertyName ?? bindingContext.ModelName;
            object model      = null;

            if (bindingContext.ModelType == typeof(string))
            {
                var value = request.Headers.Get(headerName);
                if (value != null)
                {
                    model = value;
                }
            }
            else if (typeof(IEnumerable <string>).IsAssignableFrom(bindingContext.ModelType))
            {
                var values = request.Headers.GetCommaSeparatedValues(headerName);
                if (values != null)
                {
                    model = ModelBindingHelper.ConvertValuesToCollectionType(
                        bindingContext.ModelType,
                        values);
                }
            }

            ModelValidationNode validationNode = null;

            if (model != null)
            {
                validationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    model);

                var attemptedValue      = (model as string) ?? request.Headers.Get(headerName);
                var valueProviderResult = new ValueProviderResult(model, attemptedValue, CultureInfo.InvariantCulture);
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            }

            return(Task.FromResult(
                       new ModelBindingResult(
                           model,
                           bindingContext.ModelName,
                           isModelSet: model != null,
                           validationNode: validationNode)));
        }
コード例 #17
0
        /// <inheritdoc />
        public async Task <ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            // Check if this binder applies.
            if (bindingContext.ModelType != typeof(byte[]))
            {
                return(null);
            }

            // Check for missing data case 1: There was no <input ... /> element containing this data.
            var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);

            if (valueProviderResult == null)
            {
                return(new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false));
            }

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

            // Check for missing data case 2: There was an <input ... /> element but it was left blank.
            var value = valueProviderResult.AttemptedValue;

            if (string.IsNullOrEmpty(value))
            {
                return(new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false));
            }

            try
            {
                var model          = Convert.FromBase64String(value);
                var validationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    model);

                return(new ModelBindingResult(
                           model,
                           bindingContext.ModelName,
                           isModelSet: true,
                           validationNode: validationNode));
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
            }

            // Matched the type (byte[]) only this binder supports. As in missing data cases, always tell the model
            // binding system to skip other model binders i.e. return non-null.
            return(new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false));
        }
コード例 #18
0
        public void PropertiesAreSet()
        {
            // Arrange
            var metadata      = GetModelMetadata();
            var modelStateKey = "someKey";

            // Act
            var node = new ModelValidationNode(metadata, modelStateKey);

            // Assert
            Assert.Equal(metadata, node.ModelMetadata);
            Assert.Equal(modelStateKey, node.ModelStateKey);
            Assert.NotNull(node.ChildNodes);
            Assert.Empty(node.ChildNodes);
        }
コード例 #19
0
ファイル: ModelValidationNodeTest.cs プロジェクト: Nakro/Mvc
        public void PropertiesAreSet()
        {
            // Arrange
            var metadata = GetModelMetadata();
            var modelStateKey = "someKey";

            // Act
            var node = new ModelValidationNode(metadata, modelStateKey);

            // Assert
            Assert.Equal(metadata, node.ModelMetadata);
            Assert.Equal(modelStateKey, node.ModelStateKey);
            Assert.NotNull(node.ChildNodes);
            Assert.Empty(node.ChildNodes);
        }
コード例 #20
0
        /// <inheritdoc />
        public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(CancellationToken))
            {
                var model = bindingContext.OperationBindingContext.HttpContext.RequestAborted;
                var validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model);
                return Task.FromResult(new ModelBindingResult(
                    model,
                    bindingContext.ModelName,
                    isModelSet: true,
                    validationNode: validationNode));
            }

            return Task.FromResult<ModelBindingResult>(null);
        }
コード例 #21
0
        /// <inheritdoc />
        public Task <ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(CancellationToken))
            {
                var model          = bindingContext.OperationBindingContext.HttpContext.RequestAborted;
                var validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model);
                return(Task.FromResult(new ModelBindingResult(
                                           model,
                                           bindingContext.ModelName,
                                           isModelSet: true,
                                           validationNode: validationNode)));
            }

            return(Task.FromResult <ModelBindingResult>(null));
        }
コード例 #22
0
        public void SetProperty_PropertyIsReadOnly_DoesNothing()
        {
            // Arrange
            var bindingContext   = CreateContext(GetMetadataForObject(new Person()));
            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "NonUpdateableProperty");
            var validationNode   = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult        = new ComplexModelDtoResult(model: null, validationNode: validationNode);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);

            // Assert
            // If didn't throw, success!
        }
コード例 #23
0
ファイル: ServicesModelBinder.cs プロジェクト: zt97/Mvc
        /// <inheritdoc />
        protected override Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext)
        {
            var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
            var model = requestServices.GetRequiredService(bindingContext.ModelType);
            var validationNode =
                new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model)
                {
                    SuppressValidation = true
                };

            return Task.FromResult(new ModelBindingResult(
                    model,
                    bindingContext.ModelName,
                    isModelSet: true,
                    validationNode: validationNode));
        }
コード例 #24
0
ファイル: ByteArrayModelBinder.cs プロジェクト: notami18/Mvc
        /// <inheritdoc />
        public async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            // Check if this binder applies.
            if (bindingContext.ModelType != typeof(byte[]))
            {
                return null;
            }

            // Check for missing data case 1: There was no <input ... /> element containing this data.
            var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
            if (valueProviderResult == null)
            {
                return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
            }

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

            // Check for missing data case 2: There was an <input ... /> element but it was left blank.
            var value = valueProviderResult.AttemptedValue;
            if (string.IsNullOrEmpty(value))
            {
                return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
            }

            try
            {
                var model = Convert.FromBase64String(value);
                var validationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    model);

                return new ModelBindingResult(
                    model,
                    bindingContext.ModelName,
                    isModelSet: true,
                    validationNode: validationNode);
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
            }

            // Matched the type (byte[]) only this binder supports. As in missing data cases, always tell the model
            // binding system to skip other model binders i.e. return non-null.
            return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
        }
コード例 #25
0
            public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
            {
                if (typeof(OrderStatus).IsAssignableFrom(bindingContext.ModelType))
                {
                    var request = bindingContext.OperationBindingContext.HttpContext.Request;

                    // Doing something slightly different here to make sure we don't get accidentally bound
                    // by the type converter binder.
                    OrderStatus model;
                    var isModelSet = Enum.TryParse<OrderStatus>("Status" + request.Query.Get("status"), out model);
                    var validationNode =
                     new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model);
                    return Task.FromResult(new ModelBindingResult(model, "status", isModelSet, validationNode));
                }

                return Task.FromResult<ModelBindingResult>(null);
            }
コード例 #26
0
        public void ConstructorSetsCollectionInstance()
        {
            // Arrange
            var metadata      = GetModelMetadata();
            var modelStateKey = "someKey";
            var childNodes    = new[]
            {
                new ModelValidationNode(metadata, "someKey0"),
                new ModelValidationNode(metadata, "someKey1")
            };

            // Act
            var node = new ModelValidationNode(metadata, modelStateKey, childNodes);

            // Assert
            Assert.Equal(childNodes, node.ChildNodes.ToArray());
        }
コード例 #27
0
ファイル: ModelValidationNodeTest.cs プロジェクト: Nakro/Mvc
        public void ConstructorSetsCollectionInstance()
        {
            // Arrange
            var metadata = GetModelMetadata();
            var modelStateKey = "someKey";
            var childNodes = new[]
            {
                new ModelValidationNode(metadata, "someKey0"),
                new ModelValidationNode(metadata, "someKey1")
            };

            // Act
            var node = new ModelValidationNode(metadata, modelStateKey, childNodes);

            // Assert
            Assert.Equal(childNodes, node.ChildNodes.ToArray());
        }
コード例 #28
0
        public async Task <ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (bindingContext.ModelMetadata.IsComplexType)
            {
                // this type cannot be converted
                return(null);
            }

            var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);

            if (valueProviderResult == null)
            {
                return(null); // no entry
            }

            object newModel;

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            try
            {
                newModel = valueProviderResult.ConvertTo(bindingContext.ModelType);
                ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
                var validationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    newModel);

                return(new ModelBindingResult(
                           newModel,
                           bindingContext.ModelName,
                           isModelSet: true,
                           validationNode: validationNode));
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
            }

            // Were able to find a converter for the type but conversion failed.
            // Tell the model binding system to skip other model binders i.e. return non-null.
            return(new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false));
        }
コード例 #29
0
        /// <inheritdoc />
        protected override Task<ModelBindingResult> BindModelCoreAsync([NotNull] ModelBindingContext bindingContext)
        {
            var request = bindingContext.OperationBindingContext.HttpContext.Request;
            var modelMetadata = bindingContext.ModelMetadata;

            // Property name can be null if the model metadata represents a type (rather than a property or parameter).
            var headerName = bindingContext.BinderModelName ?? modelMetadata.PropertyName ?? bindingContext.ModelName;
            object model = null;
            if (bindingContext.ModelType == typeof(string))
            {
                var value = request.Headers.Get(headerName);
                if (value != null)
                {
                    model = value;
                }
            }
            else if (typeof(IEnumerable<string>).GetTypeInfo().IsAssignableFrom(
                bindingContext.ModelType.GetTypeInfo()))
            {
                var values = request.Headers.GetCommaSeparatedValues(headerName);
                if (values != null)
                {
                    model = ModelBindingHelper.ConvertValuesToCollectionType(
                        bindingContext.ModelType,
                        values);
                }
            }

            ModelValidationNode validationNode = null;
            if (model != null)
            {
                validationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    model);
            }

            return Task.FromResult(
                new ModelBindingResult(
                    model,
                    bindingContext.ModelName,
                    isModelSet: model != null,
                    validationNode: validationNode));
        }
コード例 #30
0
        /// <inheritdoc />
        public async Task <ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            object value;

            if (bindingContext.ModelType == typeof(IFormFile))
            {
                var postedFiles = await GetFormFilesAsync(bindingContext);

                value = postedFiles.FirstOrDefault();
            }
            else if (typeof(IEnumerable <IFormFile>).IsAssignableFrom(bindingContext.ModelType))
            {
                var postedFiles = await GetFormFilesAsync(bindingContext);

                value = ModelBindingHelper.ConvertValuesToCollectionType(bindingContext.ModelType, postedFiles);
            }
            else
            {
                // This binder does not support the requested type.
                return(null);
            }

            ModelValidationNode validationNode = null;

            if (value != null)
            {
                validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value)
                {
                    SuppressValidation = true,
                };

                var valueProviderResult = new ValueProviderResult(rawValue: value);
                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            }

            return(new ModelBindingResult(
                       value,
                       bindingContext.ModelName,
                       isModelSet: value != null,
                       validationNode: validationNode));
        }
コード例 #31
0
        /// <inheritdoc />
        public async Task <ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(IFormCollection) &&
                bindingContext.ModelType != typeof(FormCollection))
            {
                return(null);
            }

            object model;
            var    request = bindingContext.OperationBindingContext.HttpContext.Request;

            if (request.HasFormContentType)
            {
                var form = await request.ReadFormAsync();

                if (bindingContext.ModelType.GetTypeInfo().IsAssignableFrom(form.GetType().GetTypeInfo()))
                {
                    model = form;
                }
                else
                {
                    var formValuesLookup = form.ToDictionary(p => p.Key, p => p.Value);
                    model = new FormCollection(formValuesLookup, form.Files);
                }
            }
            else
            {
                model = new FormCollection(new Dictionary <string, string[]>());
            }

            var validationNode =
                new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model)
            {
                SuppressValidation = true,
            };

            return(new ModelBindingResult(
                       model,
                       bindingContext.ModelName,
                       isModelSet: true,
                       validationNode: validationNode));
        }
コード例 #32
0
        public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (bindingContext.ModelMetadata.IsComplexType)
            {
                // this type cannot be converted
                return null;
            }

            var valueProviderResult = await bindingContext.ValueProvider.GetValueAsync(bindingContext.ModelName);
            if (valueProviderResult == null)
            {
                return null; // no entry
            }

            object newModel;
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            try
            {
                newModel = valueProviderResult.ConvertTo(bindingContext.ModelType);
                ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref newModel);
                var validationNode = new ModelValidationNode(
                   bindingContext.ModelName,
                   bindingContext.ModelMetadata,
                   newModel);

                return new ModelBindingResult(
                    newModel,
                    bindingContext.ModelName,
                    isModelSet: true,
                    validationNode: validationNode);
            }
            catch (Exception ex)
            {
                bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, ex);
            }

            // Were able to find a converter for the type but conversion failed.
            // Tell the model binding system to skip other model binders i.e. return non-null.
            return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
        }
コード例 #33
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorNotPresent_RegistersValidationCallback()
        {
            // Arrange
            var bindingContext    = CreateContext(GetMetadataForObject(new Person()));
            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfBirth");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult         = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);
            var validationContext = new ModelValidationContext(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(true, bindingContext.ModelState.IsValid);
            validationNode.Validate(validationContext, bindingContext.ValidationNode);
            Assert.Equal(false, bindingContext.ModelState.IsValid);
        }
コード例 #34
0
        public void SetProperty_SettingNonNullableValueTypeToNull_RequiredValidatorPresent_AddsModelError()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new Person()));

            bindingContext.ModelName = " foo";
            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "ValueTypeRequired");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo.ValueTypeRequired");
            var dtoResult         = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(false, bindingContext.ModelState.IsValid);
            Assert.Equal("Sample message", bindingContext.ModelState["foo.ValueTypeRequired"].Errors[0].ErrorMessage);
        }
コード例 #35
0
ファイル: ModelValidationNode.cs プロジェクト: Nakro/Mvc
        private object TryConvertContainerToMetadataType(ModelValidationNode parentNode)
        {
            if (parentNode != null)
            {
                var containerInstance = parentNode.ModelMetadata.Model;
                if (containerInstance != null)
                {
                    var expectedContainerType = ModelMetadata.ContainerType;
                    if (expectedContainerType != null)
                    {
                        if (expectedContainerType.IsCompatibleWith(containerInstance))
                        {
                            return containerInstance;
                        }
                    }
                }
            }

            return null;
        }
コード例 #36
0
ファイル: ModelValidationNode.cs プロジェクト: gmmateev/Mvc
        private object TryConvertContainerToMetadataType(ModelValidationNode parentNode)
        {
            if (parentNode != null)
            {
                var containerInstance = parentNode.ModelMetadata.Model;
                if (containerInstance != null)
                {
                    var expectedContainerType = ModelMetadata.ContainerType;
                    if (expectedContainerType != null)
                    {
                        if (expectedContainerType.IsCompatibleWith(containerInstance))
                        {
                            return(containerInstance);
                        }
                    }
                }
            }

            return(null);
        }
コード例 #37
0
        /// <inheritdoc />
        public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType == typeof(HttpRequestMessage))
            {
                var model = bindingContext.OperationBindingContext.HttpContext.GetHttpRequestMessage();
                var validationNode =
                    new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model)
                    {
                        SuppressValidation = true,
                    };

                return Task.FromResult(new ModelBindingResult(
                    model,
                    bindingContext.ModelName,
                    isModelSet: true,
                    validationNode: validationNode));
            }

            return Task.FromResult<ModelBindingResult>(null);
        }
コード例 #38
0
        public void CombineWith()
        {
            // Arrange
            var expected = new[]
            {
                "Validating parent1.",
                "Validating parent2.",
                "Validated parent1.",
                "Validated parent2."
            };
            var log = new List <string>();

            var allChildNodes = new[]
            {
                new ModelValidationNode(GetModelMetadata(), "key1"),
                new ModelValidationNode(GetModelMetadata(), "key2"),
                new ModelValidationNode(GetModelMetadata(), "key3"),
            };

            var parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1");

            parentNode1.ChildNodes.Add(allChildNodes[0]);
            parentNode1.Validating += (sender, e) => log.Add("Validating parent1.");
            parentNode1.Validated  += (sender, e) => log.Add("Validated parent1.");

            var parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");

            parentNode2.ChildNodes.Add(allChildNodes[1]);
            parentNode2.ChildNodes.Add(allChildNodes[2]);
            parentNode2.Validating += (sender, e) => log.Add("Validating parent2.");
            parentNode2.Validated  += (sender, e) => log.Add("Validated parent2.");
            var context = CreateContext();

            // Act
            parentNode1.CombineWith(parentNode2);
            parentNode1.Validate(context);

            // Assert
            Assert.Equal(expected, log);
            Assert.Equal(allChildNodes, parentNode1.ChildNodes.ToArray());
        }
コード例 #39
0
        public void SetProperty_SettingNullableTypeToNull_RequiredValidatorPresent_PropertySetterThrows_AddsRequiredMessageString()
        {
            // Arrange
            var bindingContext = CreateContext(GetMetadataForObject(new ModelWhosePropertySetterThrows()));

            bindingContext.ModelName = "foo";
            var propertyMetadata  = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "Name");
            var validationNode    = new ModelValidationNode(propertyMetadata, "foo.Name");
            var dtoResult         = new ComplexModelDtoResult(model: null, validationNode: validationNode);
            var requiredValidator = GetRequiredValidator(bindingContext, propertyMetadata);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator);

            // Assert
            Assert.Equal(false, bindingContext.ModelState.IsValid);
            Assert.Equal(1, bindingContext.ModelState["foo.Name"].Errors.Count);
            Assert.Equal("This message comes from the [Required] attribute.", bindingContext.ModelState["foo.Name"].Errors[0].ErrorMessage);
        }
コード例 #40
0
        public void Validate_SkipsValidationIfSuppressed()
        {
            // Arrange
            var log           = new List <string>();
            var model         = new LoggingValidatableObject(log);
            var modelMetadata = GetModelMetadata(model);
            var node          = new ModelValidationNode(modelMetadata, "theKey")
            {
                SuppressValidation = true
            };

            node.Validating += (sender, e) => log.Add("In OnValidating()");
            node.Validated  += (sender, e) => log.Add("In OnValidated()");
            var context = CreateContext();

            // Act
            node.Validate(context);

            // Assert
            Assert.Empty(log);
        }
コード例 #41
0
        public void Validate_ValidatesIfModelIsNull()
        {
            // Arrange
            var modelMetadata = GetModelMetadata(typeof(ValidateAllPropertiesModel));
            var node          = new ModelValidationNode(modelMetadata, "theKey");

            var context = CreateContext(modelMetadata);

            // Act
            node.Validate(context);

            // Assert
            var modelState = Assert.Single(context.ModelState);

            Assert.Equal("theKey", modelState.Key);
            Assert.Equal(ModelValidationState.Invalid, modelState.Value.ValidationState);

            var error = Assert.Single(modelState.Value.Errors);

            Assert.Equal("A value is required but was not present in the request.", error.ErrorMessage);
        }
コード例 #42
0
        /// <inheritdoc />
        public async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(IFormCollection) &&
                bindingContext.ModelType != typeof(FormCollection))
            {
                return null;
            }

            object model;
            var request = bindingContext.OperationBindingContext.HttpContext.Request;
            if (request.HasFormContentType)
            {
                var form = await request.ReadFormAsync();
                if (bindingContext.ModelType.GetTypeInfo().IsAssignableFrom(form.GetType().GetTypeInfo()))
                {
                    model = form;
                }
                else
                {
                    var formValuesLookup = form.ToDictionary(p => p.Key, p => p.Value);
                    model = new FormCollection(formValuesLookup, form.Files);
                }
            }
            else
            {
                model = new FormCollection(new Dictionary<string, string[]>());
            }

            var validationNode =
                 new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, model)
                 {
                     SuppressValidation = true,
                 };

            return new ModelBindingResult(
                model,
                bindingContext.ModelName,
                isModelSet: true,
                validationNode: validationNode);
        }
コード例 #43
0
        public void Validate_SkipsValidationIfHandlerCancels()
        {
            // Arrange
            var log           = new List <string>();
            var model         = new LoggingValidatableObject(log);
            var modelMetadata = GetModelMetadata(model);
            var node          = new ModelValidationNode(modelMetadata, "theKey");

            node.Validating += (sender, e) =>
            {
                log.Add("In OnValidating()");
                e.Cancel = true;
            };
            node.Validated += (sender, e) => log.Add("In OnValidated()");
            var context = CreateContext(modelMetadata);

            // Act
            node.Validate(context);

            // Assert
            Assert.Equal(new[] { "In OnValidating()" }, log.ToArray());
        }
コード例 #44
0
        public void NullCheckFailedHandler_ModelStateValid_AddsErrorString()
        {
            // Arrange
            var modelState        = new ModelStateDictionary();
            var modelMetadata     = GetMetadataForType(typeof(Person));
            var validationNode    = new ModelValidationNode(modelMetadata, "foo");
            var validationContext = new ModelValidationContext(new DataAnnotationsModelMetadataProvider(),
                                                               Mock.Of <IModelValidatorProvider>(),
                                                               modelState,
                                                               modelMetadata,
                                                               null);
            var e = new ModelValidatedEventArgs(validationContext, parentNode: null);

            // Act
            var handler = MutableObjectModelBinder.CreateNullCheckFailedHandler(modelMetadata, incomingValue: null);

            handler(validationNode, e);

            // Assert
            Assert.True(modelState.ContainsKey("foo"));
            Assert.Equal("A value is required.", modelState["foo"].Errors[0].ErrorMessage);
        }
コード例 #45
0
ファイル: ModelValidationNodeTest.cs プロジェクト: Nakro/Mvc
        public void CombineWith()
        {
            // Arrange
            var expected = new[]
            {
                "Validating parent1.",
                "Validating parent2.",
                "Validated parent1.",
                "Validated parent2."
            };
            var log = new List<string>();

            var allChildNodes = new[]
            {
                new ModelValidationNode(GetModelMetadata(), "key1"),
                new ModelValidationNode(GetModelMetadata(), "key2"),
                new ModelValidationNode(GetModelMetadata(), "key3"),
            };

            var parentNode1 = new ModelValidationNode(GetModelMetadata(), "parent1");
            parentNode1.ChildNodes.Add(allChildNodes[0]);
            parentNode1.Validating += (sender, e) => log.Add("Validating parent1.");
            parentNode1.Validated += (sender, e) => log.Add("Validated parent1.");

            var parentNode2 = new ModelValidationNode(GetModelMetadata(), "parent2");
            parentNode2.ChildNodes.Add(allChildNodes[1]);
            parentNode2.ChildNodes.Add(allChildNodes[2]);
            parentNode2.Validating += (sender, e) => log.Add("Validating parent2.");
            parentNode2.Validated += (sender, e) => log.Add("Validated parent2.");
            var context = CreateContext();

            // Act
            parentNode1.CombineWith(parentNode2);
            parentNode1.Validate(context);

            // Assert
            Assert.Equal(expected, log);
            Assert.Equal(allChildNodes, parentNode1.ChildNodes.ToArray());
        }
コード例 #46
0
        /// <inheritdoc />
        public virtual async Task <ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);
            if (!CanBindType(bindingContext.ModelMetadata))
            {
                return(null);
            }

            var mutableObjectBinderContext = new MutableObjectBinderContext()
            {
                ModelBindingContext = bindingContext,
                PropertyMetadata    = GetMetadataForProperties(bindingContext).ToArray(),
            };

            if (!(await CanCreateModel(mutableObjectBinderContext)))
            {
                return(null);
            }

            // Create model first (if necessary) to avoid reporting errors about properties when activation fails.
            var model = GetModel(bindingContext);

            var results = await BindPropertiesAsync(bindingContext, mutableObjectBinderContext.PropertyMetadata);

            var validationNode = new ModelValidationNode(
                bindingContext.ModelName,
                bindingContext.ModelMetadata,
                model);

            // Post-processing e.g. property setters and hooking up validation.
            bindingContext.Model = model;
            ProcessResults(bindingContext, results, validationNode);

            return(new ModelBindingResult(
                       model,
                       bindingContext.ModelName,
                       isModelSet: true,
                       validationNode: validationNode));
        }
コード例 #47
0
        public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
        {
            var valueProviderResult = await GetCompatibleValueProviderResult(bindingContext);
            if (valueProviderResult == null)
            {
                // conversion would have failed
                return null;
            }

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            var model = valueProviderResult.RawValue;
            ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model);
            var validationNode = new ModelValidationNode(
                  bindingContext.ModelName,
                  bindingContext.ModelMetadata,
                  model);

            return new ModelBindingResult(
                model,
                bindingContext.ModelName,
                isModelSet: true,
                validationNode: validationNode);
        }
コード例 #48
0
        public void SetProperty_PropertyIsSettable_SetterThrows_RecordsError()
        {
            // Arrange
            var model = new Person
            {
                DateOfBirth = new DateTime(1900, 1, 1)
            };
            var bindingContext = CreateContext(GetMetadataForObject(model));

            var propertyMetadata = bindingContext.ModelMetadata.Properties.Single(o => o.PropertyName == "DateOfDeath");
            var validationNode   = new ModelValidationNode(propertyMetadata, "foo");
            var dtoResult        = new ComplexModelDtoResult(new DateTime(1800, 1, 1), validationNode);

            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.SetPropertyPublic(bindingContext, propertyMetadata, dtoResult, requiredValidator: null);

            // Assert
            Assert.Equal("Date of death can't be before date of birth." + Environment.NewLine
                         + "Parameter name: value",
                         bindingContext.ModelState["foo"].Errors[0].Exception.Message);
        }
コード例 #49
0
        public void ProcessResults_NullableValueTypeProperty_NoValueSet_NoError()
        {
            // Arrange
            var model = new NullableValueTypeProperty();
            var containerMetadata = GetMetadataForType(model.GetType());
            var bindingContext = CreateContext(containerMetadata, model);

            var results = containerMetadata.Properties.ToDictionary(
                property => property,
                property => new ModelBindingResult(model: null, key: property.PropertyName, isModelSet: false));

            var testableBinder = new TestableMutableObjectModelBinder();
            var modelValidationNode = new ModelValidationNode(string.Empty, containerMetadata, model);

            // Act
            testableBinder.ProcessResults(bindingContext, results, modelValidationNode);

            // Assert
            var modelStateDictionary = bindingContext.ModelState;
            Assert.True(modelStateDictionary.IsValid);
        }
コード例 #50
0
        public virtual async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingContext bindingContext)
        {
            var newBindingContext = CreateNewBindingContext(bindingContext, bindingContext.ModelName);
            var modelBindingResult = await TryBind(newBindingContext);

            if (modelBindingResult == null &&
                bindingContext.FallbackToEmptyPrefix &&
                !string.IsNullOrEmpty(bindingContext.ModelName))
            {
                // Fall back to empty prefix.
                newBindingContext = CreateNewBindingContext(bindingContext,
                                                            modelName: string.Empty);
                modelBindingResult = await TryBind(newBindingContext);
            }

            if (modelBindingResult == null)
            {
                return null; // something went wrong
            }

            bindingContext.OperationBindingContext.BodyBindingState =
                newBindingContext.OperationBindingContext.BodyBindingState;

            var bindingKey = bindingContext.ModelName;
            if (modelBindingResult.IsModelSet)
            {
                // Update the model state key if we are bound using an empty prefix and it is a complex type.
                // This is needed as validation uses the model state key to log errors. The client validation expects
                // the errors with property names rather than the full name.
                if (newBindingContext.ModelMetadata.IsComplexType && string.IsNullOrEmpty(modelBindingResult.Key))
                {
                    // For non-complex types, if we fell back to the empty prefix, we should still be using the name
                    // of the parameter/property. Complex types have their own property names which acts as model
                    // state keys and do not need special treatment.
                    // For example :
                    //
                    // public class Model
                    // {
                    //     public int SimpleType { get; set; }
                    // }
                    // public void Action(int id, Model model)
                    // {
                    // }
                    //
                    // In this case, for the model parameter the key would be SimpleType instead of model.SimpleType.
                    // (i.e here the prefix for the model key is empty).
                    // For the id parameter the key would be id.
                    bindingKey = string.Empty;
                }
            }

            // Update the model validation node if the model binding result was set but no validation node was provided.
            // This would typically be the case where leaf level model binders, do not have to add a validation node
            // for validation to take effect. The composite being the entry point for model binders, takes care or
            // adding missing validation nodes.
            var modelValidationNode = modelBindingResult.ValidationNode;
            if (modelBindingResult.IsModelSet && modelValidationNode == null)
            {
                modelValidationNode = new ModelValidationNode(
                    bindingKey,
                    bindingContext.ModelMetadata,
                    modelBindingResult.Model);
            }

            return new ModelBindingResult(
                modelBindingResult.Model,
                bindingKey,
                modelBindingResult.IsModelSet,
                modelValidationNode);
        }
            public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
            {
                var model = "Success";
                bindingContext.ModelState.SetModelValue(
                    bindingContext.ModelName,
                    new ValueProviderResult(model, model, CultureInfo.CurrentCulture));

                var modelValidationNode = new ModelValidationNode(
                    bindingContext.ModelName,
                    bindingContext.ModelMetadata,
                    model);
                return Task.FromResult(new ModelBindingResult(model, bindingContext.ModelName, true, modelValidationNode));
            }
            public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
            {
                if (bindingContext.ModelType != typeof(Address))
                {
                    return null;
                }

                var address = new Address() { Street = "SomeStreet" };

                bindingContext.ModelState.SetModelValue(
                  ModelNames.CreatePropertyModelName(bindingContext.ModelName, "Street"),
                  new ValueProviderResult(
                      address.Street,
                      address.Street,
                      CultureInfo.CurrentCulture));

                var validationNode = new ModelValidationNode(
                  bindingContext.ModelName,
                  bindingContext.ModelMetadata,
                  address)
                {
                    ValidateAllProperties = true
                };

                return Task.FromResult(new ModelBindingResult(address, bindingContext.ModelName, true, validationNode));
            }
コード例 #53
0
            public async Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
            {
                if (typeof(Product).IsAssignableFrom(bindingContext.ModelType))
                {
                    var model = (Product)Activator.CreateInstance(bindingContext.ModelType);

                    model.BinderType = GetType();

                    var key =
                        string.IsNullOrEmpty(bindingContext.ModelName) ?
                        "productId" :
                        bindingContext.ModelName + "." + "productId";

                    var value = await bindingContext.ValueProvider.GetValueAsync(key);
                    model.ProductId = (int)value.ConvertTo(typeof(int));

                    var validationNode =
                        new ModelValidationNode(bindingContext.ModelName, bindingContext.ModelMetadata, value);
                    return new ModelBindingResult(model, key, true, validationNode);
                }

                return null;
            }
コード例 #54
0
        public void ProcessResults_ProvideRequiredFields_Success()
        {
            // Arrange
            var model = new Person();
            var containerMetadata = GetMetadataForType(model.GetType());

            var bindingContext = CreateContext(containerMetadata, model);
            var modelStateDictionary = bindingContext.ModelState;

            var results = containerMetadata.Properties.ToDictionary(
                property => property,
                property => new ModelBindingResult(model: null, key: property.PropertyName, isModelSet: false));
            var testableBinder = new TestableMutableObjectModelBinder();

            // Make ValueTypeRequired valid.
            var propertyMetadata = containerMetadata.Properties[nameof(Person.ValueTypeRequired)];
            results[propertyMetadata] = new ModelBindingResult(
                model: 41,
                isModelSet: true,
                key: "theModel." + nameof(Person.ValueTypeRequired));

            // Make ValueTypeRequiredWithDefaultValue valid.
            propertyMetadata = containerMetadata.Properties[nameof(Person.ValueTypeRequiredWithDefaultValue)];
            results[propertyMetadata] = new ModelBindingResult(
                model: 57,
                isModelSet: true,
                key: "theModel." + nameof(Person.ValueTypeRequiredWithDefaultValue));

            // Also remind ProcessResults about PropertyWithDefaultValue -- as BindPropertiesAsync() would.
            propertyMetadata = containerMetadata.Properties[nameof(Person.PropertyWithDefaultValue)];
            results[propertyMetadata] = new ModelBindingResult(
                model: null,
                isModelSet: false,
                key: "theModel." + nameof(Person.PropertyWithDefaultValue));
            var modelValidationNode = new ModelValidationNode(string.Empty, containerMetadata, model);

            // Act
            testableBinder.ProcessResults(bindingContext, results, modelValidationNode);

            // Assert
            Assert.True(modelStateDictionary.IsValid);
            Assert.Empty(modelStateDictionary);

            // Model gets provided values.
            Assert.Equal(41, model.ValueTypeRequired);
            Assert.Equal(57, model.ValueTypeRequiredWithDefaultValue);
            Assert.Equal(0m, model.PropertyWithDefaultValue);     // [DefaultValue] has no effect
        }
コード例 #55
0
        public void ProcessResults_ValueTypePropertyWithBindRequired_SetToNull_CapturesException()
        {
            // Arrange
            var model = new ModelWithBindRequired
            {
                Name = "original value",
                Age = -20
            };

            var containerMetadata = GetMetadataForType(model.GetType());
            var bindingContext = new ModelBindingContext()
            {
                Model = model,
                ModelMetadata = containerMetadata,
                ModelName = "theModel",
                ModelState = new ModelStateDictionary(),
                OperationBindingContext = new OperationBindingContext
                {
                    MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
                    ValidatorProvider = Mock.Of<IModelValidatorProvider>()
                }
            };

            var results = containerMetadata.Properties.ToDictionary(
                property => property,
                property => new ModelBindingResult(model: null, key: property.PropertyName, isModelSet: false));
            var propertyMetadata = containerMetadata.Properties[nameof(model.Name)];
            results[propertyMetadata] = new ModelBindingResult("John Doe", isModelSet: true, key: "theModel.Name");

            // Attempt to set non-Nullable property to null. BindRequiredAttribute should not be relevant in this
            // case because the binding exists.
            propertyMetadata = containerMetadata.Properties[nameof(model.Age)];
            results[propertyMetadata] = new ModelBindingResult(model: null, isModelSet: true, key: "theModel.Age");

            var testableBinder = new TestableMutableObjectModelBinder();
            var modelValidationNode = new ModelValidationNode(string.Empty, containerMetadata, model);

            // Act
            testableBinder.ProcessResults(bindingContext, results, modelValidationNode);

            // Assert
            var modelStateDictionary = bindingContext.ModelState;
            Assert.False(modelStateDictionary.IsValid);
            Assert.Equal(1, modelStateDictionary.Count);

            // Check Age error.
            ModelState modelState;
            Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState));
            Assert.Equal(ModelValidationState.Invalid, modelState.ValidationState);

            var modelError = Assert.Single(modelState.Errors);
            Assert.Equal(string.Empty, modelError.ErrorMessage);
            Assert.IsType<NullReferenceException>(modelError.Exception);
        }
コード例 #56
0
        public void ProcessResults_Success()
        {
            // Arrange
            var dob = new DateTime(2001, 1, 1);
            var model = new PersonWithBindExclusion
            {
                DateOfBirth = dob
            };
            var containerMetadata = GetMetadataForType(model.GetType());

            var bindingContext = CreateContext(containerMetadata, model);
            var results = containerMetadata.Properties.ToDictionary(
                property => property,
                property => new ModelBindingResult(model: null, key: property.PropertyName, isModelSet: false));

            var firstNameProperty = containerMetadata.Properties[nameof(model.FirstName)];
            results[firstNameProperty] = new ModelBindingResult(
                model: "John",
                isModelSet: true,
                key: nameof(model.FirstName));

            var lastNameProperty = containerMetadata.Properties[nameof(model.LastName)];
            results[lastNameProperty] = new ModelBindingResult(
                model: "Doe",
                isModelSet: true,
                key: nameof(model.LastName));

            var modelValidationNode = new ModelValidationNode(string.Empty, containerMetadata, model);
            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.ProcessResults(bindingContext, results, modelValidationNode);

            // Assert
            Assert.Equal("John", model.FirstName);
            Assert.Equal("Doe", model.LastName);
            Assert.Equal(dob, model.DateOfBirth);
            Assert.True(bindingContext.ModelState.IsValid);

            // Ensure that we add child nodes for all the nodes which have a result (irrespective of if they
            // are bound or not).
            Assert.Equal(5, modelValidationNode.ChildNodes.Count);

            Assert.Collection(modelValidationNode.ChildNodes,
                child =>
                {
                    Assert.Equal(nameof(model.DateOfBirth), child.Key);
                    Assert.Equal(null, child.Model);
                },
                child =>
                {
                    Assert.Equal(nameof(model.DateOfDeath), child.Key);
                    Assert.Equal(null, child.Model);
                },
                child =>
                {
                    Assert.Equal(nameof(model.FirstName), child.Key);
                    Assert.Equal("John", child.Model);
                },
                child =>
                {
                    Assert.Equal(nameof(model.LastName), child.Key);
                    Assert.Equal("Doe", child.Model);
                },
                child =>
                {
                    Assert.Equal(nameof(model.NonUpdateableProperty), child.Key);
                    Assert.Equal(null, child.Model);
                });
        }
コード例 #57
0
        public void ProcessResults_ReferenceTypePropertyWithBindRequired_RequiredValidatorIgnored()
        {
            // Arrange
            var model = new ModelWithBindRequiredAndRequiredAttribute();
            var containerMetadata = GetMetadataForType(model.GetType());

            var bindingContext = CreateContext(containerMetadata, model);
            var modelStateDictionary = bindingContext.ModelState;

            var results = containerMetadata.Properties.ToDictionary(
                property => property,
                property => new ModelBindingResult(model: null, key: property.PropertyName, isModelSet: false));
            var testableBinder = new TestableMutableObjectModelBinder();

            // Make ValueTypeProperty have a value.
            var propertyMetadata = containerMetadata
                .Properties[nameof(ModelWithBindRequiredAndRequiredAttribute.ValueTypeProperty)];
            results[propertyMetadata] = new ModelBindingResult(
                model: 17,
                isModelSet: true,
                key: "theModel." + nameof(ModelWithBindRequiredAndRequiredAttribute.ValueTypeProperty));

            // Make ReferenceTypeProperty not have a value.
            propertyMetadata = containerMetadata
                .Properties[nameof(ModelWithBindRequiredAndRequiredAttribute.ReferenceTypeProperty)];
            results[propertyMetadata] = new ModelBindingResult(
                model: null,
                isModelSet: false,
                key: "theModel." + nameof(ModelWithBindRequiredAndRequiredAttribute.ReferenceTypeProperty));

            var modelValidationNode = new ModelValidationNode(string.Empty, containerMetadata, model);

            // Act
            testableBinder.ProcessResults(bindingContext, results, modelValidationNode);

            // Assert
            Assert.False(modelStateDictionary.IsValid);

            var entry = Assert.Single(
                modelStateDictionary,
                kvp => kvp.Key == "theModel." + nameof(ModelWithBindRequiredAndRequiredAttribute.ReferenceTypeProperty))
                .Value;
            var error = Assert.Single(entry.Errors);
            Assert.Null(error.Exception);
            Assert.Equal("A value for the 'ReferenceTypeProperty' property was not provided.", error.ErrorMessage);

            // Model gets provided values.
            Assert.Equal(17, model.ValueTypeProperty);
            Assert.Null(model.ReferenceTypeProperty);
        }
コード例 #58
0
        public void ProcessResults_DataMemberIsRequiredFieldMissing_RaisesModelError()
        {
            // Arrange
            var model = new ModelWithDataMemberIsRequired
            {
                Name = "original value",
                Age = -20
            };

            var containerMetadata = GetMetadataForType(model.GetType());
            var bindingContext = new ModelBindingContext
            {
                Model = model,
                ModelMetadata = containerMetadata,
                ModelName = "theModel",
                OperationBindingContext = new OperationBindingContext
                {
                    MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
                    ValidatorProvider = Mock.Of<IModelValidatorProvider>()
                }
            };

            var results = containerMetadata.Properties.ToDictionary(
                property => property,
                property => new ModelBindingResult(model: null, key: property.PropertyName, isModelSet: false));
            var nameProperty = containerMetadata.Properties[nameof(model.Name)];
            results[nameProperty] = new ModelBindingResult("John Doe", isModelSet: true, key: string.Empty);

            var modelValidationNode = new ModelValidationNode(string.Empty, containerMetadata, model);
            var testableBinder = new TestableMutableObjectModelBinder();

            // Act
            testableBinder.ProcessResults(bindingContext, results, modelValidationNode);

            // Assert
            var modelStateDictionary = bindingContext.ModelState;
            Assert.False(modelStateDictionary.IsValid);
            Assert.Single(modelStateDictionary);

            // Check Age error.
            ModelState modelState;
            Assert.True(modelStateDictionary.TryGetValue("theModel.Age", out modelState));
            var modelError = Assert.Single(modelState.Errors);
            Assert.Null(modelError.Exception);
            Assert.NotNull(modelError.ErrorMessage);
            Assert.Equal("A value for the 'Age' property was not provided.", modelError.ErrorMessage);
        }
コード例 #59
0
        public void ProcessResults_ValueTypeProperty_TriesToSetNullModel_CapturesException()
        {
            // Arrange
            var model = new Person();
            var containerMetadata = GetMetadataForType(model.GetType());

            var bindingContext = CreateContext(containerMetadata, model);
            var modelStateDictionary = bindingContext.ModelState;

            var results = containerMetadata.Properties.ToDictionary(
                property => property,
                property => new ModelBindingResult(model: null, key: property.PropertyName, isModelSet: false));
            var testableBinder = new TestableMutableObjectModelBinder();

            // The [DefaultValue] on ValueTypeRequiredWithDefaultValue is ignored by model binding.
            var expectedValue = 0;

            // Make ValueTypeRequired invalid.
            var propertyMetadata = containerMetadata.Properties[nameof(Person.ValueTypeRequired)];
            results[propertyMetadata] = new ModelBindingResult(
                model: null,
                isModelSet: true,
                key: "theModel." + nameof(Person.ValueTypeRequired));

            // Make ValueTypeRequiredWithDefaultValue invalid
            propertyMetadata = containerMetadata.Properties[nameof(Person.ValueTypeRequiredWithDefaultValue)];
            results[propertyMetadata] = new ModelBindingResult(
                model: null,
                isModelSet: true,
                key: "theModel." + nameof(Person.ValueTypeRequiredWithDefaultValue));

            var modelValidationNode = new ModelValidationNode(string.Empty, containerMetadata, model);

            // Act
            testableBinder.ProcessResults(bindingContext, results, modelValidationNode);

            // Assert
            Assert.False(modelStateDictionary.IsValid);

            // Check ValueTypeRequired error.
            var modelStateEntry = Assert.Single(
                modelStateDictionary,
                entry => entry.Key == "theModel." + nameof(Person.ValueTypeRequired));
            Assert.Equal("theModel." + nameof(Person.ValueTypeRequired), modelStateEntry.Key);

            var modelState = modelStateEntry.Value;
            Assert.Equal(ModelValidationState.Invalid, modelState.ValidationState);

            var error = Assert.Single(modelState.Errors);
            Assert.Equal(string.Empty, error.ErrorMessage);
            Assert.IsType<NullReferenceException>(error.Exception);

            // Check ValueTypeRequiredWithDefaultValue error.
            modelStateEntry = Assert.Single(
                modelStateDictionary,
                entry => entry.Key == "theModel." + nameof(Person.ValueTypeRequiredWithDefaultValue));
            Assert.Equal("theModel." + nameof(Person.ValueTypeRequiredWithDefaultValue), modelStateEntry.Key);

            modelState = modelStateEntry.Value;
            Assert.Equal(ModelValidationState.Invalid, modelState.ValidationState);

            error = Assert.Single(modelState.Errors);
            Assert.Equal(string.Empty, error.ErrorMessage);
            Assert.IsType<NullReferenceException>(error.Exception);

            Assert.Equal(0, model.ValueTypeRequired);
            Assert.Equal(expectedValue, model.ValueTypeRequiredWithDefaultValue);
        }