コード例 #1
0
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        _logger.AttemptingToBindModel(bindingContext);

        var keyModelName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, "Key");
        var keyResult    = await TryBindStrongModel <TKey?>(bindingContext, _keyBinder, "Key", keyModelName);

        var valueModelName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, "Value");
        var valueResult    = await TryBindStrongModel <TValue?>(bindingContext, _valueBinder, "Value", valueModelName);

        if (keyResult.IsModelSet && valueResult.IsModelSet)
        {
            var model = new KeyValuePair <TKey?, TValue?>(
                ModelBindingHelper.CastOrDefault <TKey?>(keyResult.Model),
                ModelBindingHelper.CastOrDefault <TValue?>(valueResult.Model));

            bindingContext.Result = ModelBindingResult.Success(model);
            _logger.DoneAttemptingToBindModel(bindingContext);
            return;
        }

        if (!keyResult.IsModelSet && valueResult.IsModelSet)
        {
            bindingContext.ModelState.TryAddModelError(
                keyModelName,
                bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingKeyOrValueAccessor());
            _logger.DoneAttemptingToBindModel(bindingContext);
            return;
        }

        if (keyResult.IsModelSet && !valueResult.IsModelSet)
        {
            bindingContext.ModelState.TryAddModelError(
                valueModelName,
                bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingKeyOrValueAccessor());
            _logger.DoneAttemptingToBindModel(bindingContext);
            return;
        }

        // If we failed to find data for a top-level model, then generate a
        // default 'empty' model and return it.
        if (bindingContext.IsTopLevelObject)
        {
            var model = new KeyValuePair <TKey?, TValue?>();
            bindingContext.Result = ModelBindingResult.Success(model);
        }
        _logger.DoneAttemptingToBindModel(bindingContext);
    }
コード例 #2
0
 private static string GetName(string containerName, ApiParameterDescriptionContext metadata)
 {
     if (!string.IsNullOrEmpty(metadata.BinderModelName))
     {
         // Name was explicitly provided
         return(metadata.BinderModelName);
     }
     else
     {
         return(ModelBindingHelper.CreatePropertyModelName(containerName, metadata.PropertyName));
     }
 }
コード例 #3
0
            public override IEnumerable <ModelValidationResult> Validate(
                ModelMetadata metadata,
                object container
                )
            {
                bool propertiesValid = true;

                foreach (ModelMetadata propertyMetadata in metadata.Properties)
                {
                    foreach (
                        ModelValidator propertyValidator in propertyMetadata.GetValidators(
                            ValidatorProviders
                            )
                        )
                    {
                        foreach (
                            ModelValidationResult propertyResult in propertyValidator.Validate(
                                metadata,
                                container
                                )
                            )
                        {
                            propertiesValid = false;
                            yield return(new ModelValidationResult
                            {
                                MemberName = ModelBindingHelper.CreatePropertyModelName(
                                    propertyMetadata.PropertyName,
                                    propertyResult.MemberName
                                    ),
                                Message = propertyResult.Message
                            });
                        }
                    }
                }

                if (propertiesValid)
                {
                    foreach (
                        ModelValidator typeValidator in metadata.GetValidators(ValidatorProviders)
                        )
                    {
                        foreach (
                            ModelValidationResult typeResult in typeValidator.Validate(
                                metadata,
                                container
                                )
                            )
                        {
                            yield return(typeResult);
                        }
                    }
                }
            }
コード例 #4
0
        public virtual bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            EnsureModel(actionContext, bindingContext);
            IEnumerable <ModelMetadata> propertyMetadatas = GetMetadataForProperties(actionContext, bindingContext);
            ComplexModelDto             dto = CreateAndPopulateDto(actionContext, bindingContext, propertyMetadatas);

            // post-processing, e.g. property setters and hooking up validation
            ProcessDto(actionContext, bindingContext, dto);
            bindingContext.ValidationNode.ValidateAllProperties = true; // complex models require full validation
            return(true);
        }
コード例 #5
0
        public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
            {
                return(CollectionModelBinderUtil.GetGenericBinder(typeof(ICollection <>), typeof(List <>), typeof(CollectionModelBinder <>), bindingContext.ModelMetadata));
            }
            else
            {
                return(null);
            }
        }
コード例 #6
0
        public virtual bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            List <TElement>     boundCollection     = (valueProviderResult != null)
                                                 ? BindSimpleCollection(actionContext, bindingContext, valueProviderResult.RawValue, valueProviderResult.Culture)
                                                 : BindComplexCollection(actionContext, bindingContext);

            bool retVal = CreateOrReplaceCollection(actionContext, bindingContext, boundCollection);

            return(retVal);
        }
コード例 #7
0
        public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (!bindingContext.ModelMetadata.IsReadOnly && bindingContext.ModelType.IsArray &&
                bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
            {
                Type elementType = bindingContext.ModelType.GetElementType();
                return((IModelBinder)Activator.CreateInstance(typeof(ArrayModelBinder <>).MakeGenericType(elementType)));
            }

            return(null);
        }
コード例 #8
0
        public async Task TryUpdateModel_UsingIncludeExpressionOverload_ReturnsTrue_ModelBindsAndValidatesSuccessfully()
        {
            // Arrange
            var binders = new IModelBinder[]
            {
                new TypeConverterModelBinder(),
                new ComplexModelDtoModelBinder(),
                new MutableObjectModelBinder()
            };

            var validator = new DataAnnotationsModelValidatorProvider();
            var model     = new MyModel
            {
                MyProperty       = "Old-Value",
                IncludedProperty = "Old-IncludedPropertyValue",
                ExcludedProperty = "Old-ExcludedPropertyValue"
            };

            var modelStateDictionary = new ModelStateDictionary();
            var values = new Dictionary <string, object>
            {
                { "", null },
                { "MyProperty", "MyPropertyValue" },
                { "IncludedProperty", "IncludedPropertyValue" },
                { "ExcludedProperty", "ExcludedPropertyValue" }
            };

            var valueProvider    = new TestValueProvider(values);
            var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();

            // Act
            var result = await ModelBindingHelper.TryUpdateModelAsync(
                model,
                "",
                Mock.Of <HttpContext>(),
                modelStateDictionary,
                TestModelMetadataProvider.CreateDefaultProvider(),
                GetCompositeBinder(binders),
                valueProvider,
                new List <IInputFormatter>(),
                new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider),
                validator,
                m => m.IncludedProperty,
                m => m.MyProperty);

            // Assert
            Assert.True(result);
            Assert.Equal("MyPropertyValue", model.MyProperty);
            Assert.Equal("IncludedPropertyValue", model.IncludedProperty);
            Assert.Equal("Old-ExcludedPropertyValue", model.ExcludedProperty);
        }
コード例 #9
0
        public void ClearValidationStateForCollectionsModel_EmtpyModelKey(string modelKey)
        {
            // Arrange
            var metadataProvider = new EmptyModelMetadataProvider();
            var dictionary       = new ModelStateDictionary();

            dictionary["[0].Name"] = new ModelState {
                ValidationState = ModelValidationState.Invalid
            };
            dictionary.AddModelError("[0].Name", "Name invalid.");
            dictionary["[0].Id"] = new ModelState {
                ValidationState = ModelValidationState.Invalid
            };
            dictionary.AddModelError("[0].Id", "Id invalid.");
            dictionary.AddModelError("[0].Id", "Id required.");
            dictionary["[0].Category"] = new ModelState {
                ValidationState = ModelValidationState.Valid
            };

            dictionary["[1].Name"] = new ModelState {
                ValidationState = ModelValidationState.Valid
            };
            dictionary["[1].Id"] = new ModelState {
                ValidationState = ModelValidationState.Valid
            };
            dictionary["[1].Category"] = new ModelState {
                ValidationState = ModelValidationState.Invalid
            };
            dictionary.AddModelError("[1].Category", "Category invalid.");

            // Act
            ModelBindingHelper.ClearValidationStateForModel(
                typeof(List <Product>),
                dictionary,
                metadataProvider,
                modelKey);

            // Assert
            Assert.Equal(0, dictionary["[0].Name"].Errors.Count);
            Assert.Equal(ModelValidationState.Unvalidated, dictionary["[0].Name"].ValidationState);
            Assert.Equal(0, dictionary["[0].Id"].Errors.Count);
            Assert.Equal(ModelValidationState.Unvalidated, dictionary["[0].Id"].ValidationState);
            Assert.Equal(0, dictionary["[0].Category"].Errors.Count);
            Assert.Equal(ModelValidationState.Unvalidated, dictionary["[0].Category"].ValidationState);
            Assert.Equal(0, dictionary["[1].Name"].Errors.Count);
            Assert.Equal(ModelValidationState.Unvalidated, dictionary["[1].Name"].ValidationState);
            Assert.Equal(0, dictionary["[1].Id"].Errors.Count);
            Assert.Equal(ModelValidationState.Unvalidated, dictionary["[1].Id"].ValidationState);
            Assert.Equal(0, dictionary["[1].Category"].Errors.Count);
            Assert.Equal(ModelValidationState.Unvalidated, dictionary["[1].Category"].ValidationState);
        }
コード例 #10
0
        internal static List <TElement> BindComplexCollectionFromIndexes(HttpActionContext actionContext, ModelBindingContext bindingContext, IEnumerable <string> indexNames)
        {
            bool indexNamesIsFinite;

            if (indexNames != null)
            {
                indexNamesIsFinite = true;
            }
            else
            {
                indexNamesIsFinite = false;
                indexNames         = CollectionModelBinderUtil.GetZeroBasedIndexes();
            }

            List <TElement> boundCollection = new List <TElement>();

            foreach (string indexName in indexNames)
            {
                string fullChildName = ModelBindingHelper.CreateIndexModelName(bindingContext.ModelName, indexName);
                ModelBindingContext childBindingContext = new ModelBindingContext(bindingContext)
                {
                    ModelMetadata = actionContext.GetMetadataProvider().GetMetadataForType(null, typeof(TElement)),
                    ModelName     = fullChildName
                };

                bool         didBind    = false;
                object       boundValue = null;
                IModelBinder childBinder;
                if (actionContext.TryGetBinder(childBindingContext, out childBinder))
                {
                    didBind = childBinder.BindModel(actionContext, childBindingContext);
                    if (didBind)
                    {
                        boundValue = childBindingContext.Model;

                        // merge validation up
                        bindingContext.ValidationNode.ChildNodes.Add(childBindingContext.ValidationNode);
                    }
                }

                // infinite size collection stops on first bind failure
                if (!didBind && !indexNamesIsFinite)
                {
                    break;
                }

                boundCollection.Add(ModelBindingHelper.CastOrDefault <TElement>(boundValue));
            }

            return(boundCollection);
        }
コード例 #11
0
        public async Task TryUpdateModel_UsingIncludePredicateOverload_ReturnsTrue_ModelBindsAndValidatesSuccessfully()
        {
            // Arrange
            var binders = new IModelBinder[]
            {
                new TypeConverterModelBinder(),
                new ComplexModelDtoModelBinder(),
                new MutableObjectModelBinder()
            };

            var validator = new DataAnnotationsModelValidatorProvider();
            var model     = new MyModel {
                MyProperty       = "Old-Value",
                IncludedProperty = "Old-IncludedPropertyValue",
                ExcludedProperty = "Old-ExcludedPropertyValue"
            };

            var modelStateDictionary = new ModelStateDictionary();
            var values = new Dictionary <string, object>
            {
                { "", null },
                { "MyProperty", "MyPropertyValue" },
                { "IncludedProperty", "IncludedPropertyValue" },
                { "ExcludedProperty", "ExcludedPropertyValue" }
            };

            Func <ModelBindingContext, string, bool> includePredicate =
                (context, propertyName) =>
                string.Equals(propertyName, "IncludedProperty", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(propertyName, "MyProperty", StringComparison.OrdinalIgnoreCase);

            var valueProvider = new DictionaryBasedValueProvider <TestValueBinderMetadata>(values);

            // Act
            var result = await ModelBindingHelper.TryUpdateModelAsync(
                model,
                "",
                Mock.Of <HttpContext>(),
                modelStateDictionary,
                new DataAnnotationsModelMetadataProvider(),
                GetCompositeBinder(binders),
                valueProvider,
                validator,
                includePredicate);

            // Assert
            Assert.True(result);
            Assert.Equal("MyPropertyValue", model.MyProperty);
            Assert.Equal("IncludedPropertyValue", model.IncludedProperty);
            Assert.Equal("Old-ExcludedPropertyValue", model.ExcludedProperty);
        }
コード例 #12
0
        /// <summary>
        /// Attempts to convert the values in <paramref name="result"/> to the specified type.
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> for conversion.</typeparam>
        /// <param name="result">The <see cref="ValueProviderResult"/>.</param>
        /// <returns>
        /// The converted value, or the default value of <typeparamref name="T"/> if the value could not be converted.
        /// </returns>
        /// <remarks>
        /// Copyright (c) .NET Foundation and Contributors
        /// All rights reserved.
        /// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
        /// this file except in compliance with the License.You may obtain a copy of the license at:
        /// http://www.apache.org/licenses/LICENSE-2.0
        /// Unless required by applicable law or agreed to in writing, software distributed
        /// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
        /// CONDITIONS OF ANY KIND, either express or implied. See the License for the
        /// specific language governing permissions and limitations under the License.
        /// </remarks>
        private static T ConvertTo <T>(ValueProviderResult result)
        {
            object valueToConvert = null;

            if (result.Values.Count == 1)
            {
                valueToConvert = result.Values[0];
            }
            else if (result.Values.Count > 1)
            {
                valueToConvert = result.Values.ToArray();
            }
            return(ModelBindingHelper.ConvertTo <T>(valueToConvert, result.Culture));
        }
コード例 #13
0
        /// <summary>
        /// Validate a single node, not including its children.
        /// </summary>
        /// <param name="metadata">The <see cref="ModelMetadata"/>.</param>
        /// <param name="validationContext">The <see cref="BodyModelValidatorContext"/>.</param>
        /// <param name="container">The object to validate.</param>
        /// <param name="validators">The collection of <see cref="ModelValidator"/>s.</param>
        /// <returns>
        /// <see langword="true"/> if validation succeeds for the given <paramref name="metadata"/> and
        /// <paramref name="container"/>; <see langword="false"/> otherwise.
        /// </returns>
        protected virtual bool ShallowValidate(
            ModelMetadata metadata,
            BodyModelValidatorContext validationContext,
            object container,
            IEnumerable <ModelValidator> validators)
        {
            if (metadata == null)
            {
                throw Error.ArgumentNull("metadata");
            }
            if (validationContext == null)
            {
                throw Error.ArgumentNull("validationContext");
            }
            if (validators == null)
            {
                throw Error.ArgumentNull("validators");
            }

            bool   isValid  = true;
            string modelKey = null;

            // When the are no validators we bail quickly. This saves a GetEnumerator allocation.
            // In a large array (tens of thousands or more) scenario it's very significant.
            ICollection validatorsAsCollection = validators as ICollection;

            if (validatorsAsCollection != null && validatorsAsCollection.Count == 0)
            {
                return(isValid);
            }

            foreach (ModelValidator validator in validators)
            {
                foreach (ModelValidationResult error in validator.Validate(metadata, container))
                {
                    if (modelKey == null)
                    {
                        modelKey = validationContext.RootPrefix;
                        foreach (IBodyModelValidatorKeyBuilder keyBuilder in validationContext.KeyBuilders.Reverse())
                        {
                            modelKey = keyBuilder.AppendTo(modelKey);
                        }
                    }
                    string errorKey = ModelBindingHelper.CreatePropertyModelName(modelKey, error.MemberName);
                    validationContext.ModelState.AddModelError(errorKey, error.Message);
                    isValid = false;
                }
            }
            return(isValid);
        }
コード例 #14
0
        /// <inheritdoc />
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }

            var request = bindingContext.HttpContext.Request;

            // Property name can be null if the model metadata represents a type (rather than a property or parameter).
            var headerName = bindingContext.FieldName;

            object model;

            if (bindingContext.ModelType == typeof(string))
            {
                var value = request.Headers[headerName];
                model = (string)value;
            }
            else if (ModelBindingHelper.CanGetCompatibleCollection <string>(bindingContext))
            {
                var values = request.Headers.GetCommaSeparatedValues(headerName);
                model = GetCompatibleCollection(bindingContext, values);
            }
            else
            {
                // An unsupported datatype or a new collection is needed (perhaps because target type is an array) but
                // can't assign it to the property.
                model = null;
            }

            if (model == null)
            {
                // Silently fail if unable to create an instance or use the current instance. Also reach here in the
                // typeof(string) case if the header does not exist in the request and in the
                // typeof(IEnumerable<string>) case if the header does not exist and this is not a top-level object.
                bindingContext.Result = ModelBindingResult.Failed(bindingContext.ModelName);
            }
            else
            {
                bindingContext.ModelState.SetModelValue(
                    bindingContext.ModelName,
                    request.Headers.GetCommaSeparatedValues(headerName),
                    request.Headers[headerName]);

                bindingContext.Result = ModelBindingResult.Success(bindingContext.ModelName, model);
            }

            return(TaskCache.CompletedTask);
        }
コード例 #15
0
        private static bool ValidateProperties(ModelMetadata metadata, ValidationContext validationContext, string prefix)
        {
            bool isValid = true;

            foreach (ModelMetadata childMetadata in metadata.Properties)
            {
                string childPrefix = ModelBindingHelper.CreatePropertyModelName(prefix, childMetadata.PropertyName);
                if (!ValidateNodeAndChildren(childMetadata, validationContext, metadata.Model, childPrefix))
                {
                    isValid = false;
                }
            }
            return(isValid);
        }
コード例 #16
0
        public void GetPropertyName_FieldExpression_Throws()
        {
            // Arrange
            Expression <Func <User, object> > expression = m => m._userId;

            // Act & Assert
            var ex = Assert.Throws <InvalidOperationException>(() =>
                                                               ModelBindingHelper.GetPropertyName(expression.Body));

            Assert.Equal(string.Format("The passed expression of expression node type '{0}' is invalid." +
                                       " Only simple member access expressions for model properties are supported.",
                                       expression.Body.NodeType),
                         ex.Message);
        }
コード例 #17
0
        public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (bindingContext.ModelType == ModelType)
            {
                if (SuppressPrefixCheck || bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
                {
                    return(_modelBinderFactory());
                }
            }

            return(null);
        }
コード例 #18
0
        public async Task TryUpdateModel_UsingDefaultIncludeOverload_IncludesAllProperties()
        {
            // Arrange
            var binders = new IModelBinder[]
            {
                new TypeConverterModelBinder(),
                new ComplexModelDtoModelBinder(),
                new MutableObjectModelBinder()
            };

            var validator = new DataAnnotationsModelValidatorProvider();
            var model     = new MyModel
            {
                MyProperty       = "Old-Value",
                IncludedProperty = "Old-IncludedPropertyValue",
                ExcludedProperty = "Old-ExcludedPropertyValue"
            };

            var modelStateDictionary = new ModelStateDictionary();
            var values = new Dictionary <string, object>
            {
                { "", null },
                { "MyProperty", "MyPropertyValue" },
                { "IncludedProperty", "IncludedPropertyValue" },
                { "ExcludedProperty", "ExcludedPropertyValue" }
            };

            var valueProvider    = new TestValueProvider(values);
            var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();

            // Act
            var result = await ModelBindingHelper.TryUpdateModelAsync(
                model,
                "",
                Mock.Of <HttpContext>(),
                modelStateDictionary,
                metadataProvider,
                GetCompositeBinder(binders),
                valueProvider,
                new DefaultObjectValidator(Mock.Of <IValidationExcludeFiltersProvider>(), metadataProvider),
                validator);

            // Assert
            // Includes everything.
            Assert.True(result);
            Assert.Equal("MyPropertyValue", model.MyProperty);
            Assert.Equal("IncludedPropertyValue", model.IncludedProperty);
            Assert.Equal("ExcludedPropertyValue", model.ExcludedProperty);
        }
コード例 #19
0
 private Task <bool> TryUpdateModel(
     object model,
     string prefix,
     ModelBindingTestContext testContext)
 {
     return(ModelBindingHelper.TryUpdateModelAsync(
                model,
                model.GetType(),
                prefix,
                testContext,
                testContext.MetadataProvider,
                TestModelBinderFactory.CreateDefault(),
                new CompositeValueProvider(testContext.ValueProviders),
                ModelBindingTestHelper.GetObjectValidator(testContext.MetadataProvider)));
 }
コード例 #20
0
        public void LogError(string errorPath, Exception exception)
        {
            if (errorPath == null)
            {
                throw Error.ArgumentNull("errorPath");
            }
            if (exception == null)
            {
                throw Error.ArgumentNull("exception");
            }

            string key = ModelBindingHelper.ConcatenateKeys(_prefix, errorPath);

            _modelState.AddModelError(key, exception);
        }
コード例 #21
0
        public void LogError(string errorPath, string errorMessage)
        {
            if (errorPath == null)
            {
                throw Error.ArgumentNull("errorPath");
            }
            if (errorMessage == null)
            {
                throw Error.ArgumentNull("errorMessage");
            }

            string key = ModelBindingHelper.ConcatenateKeys(_prefix, errorPath);

            _modelState.AddModelError(key, errorMessage);
        }
コード例 #22
0
        internal void ProcessDto(HttpActionContext actionContext, ModelBindingContext bindingContext, ComplexModelDto dto)
        {
            HashSet <string> requiredProperties;
            Dictionary <string, ModelValidator> requiredValidators;
            HashSet <string> skipProperties;

            GetRequiredPropertiesCollection(actionContext, bindingContext, out requiredProperties, out requiredValidators, out skipProperties);

            // Eliminate provided properties from requiredProperties; leaving just *missing* required properties.
            requiredProperties.ExceptWith(dto.Results.Select(r => r.Key.PropertyName));

            foreach (string missingRequiredProperty in requiredProperties)
            {
                string modelStateKey = ModelBindingHelper.CreatePropertyModelName(
                    bindingContext.ValidationNode.ModelStateKey, missingRequiredProperty);

                // Update Model as SetProperty() would: Place null value where validator will check for non-null. This
                // ensures a failure result from a required validator (if any) even for a non-nullable property.
                // (Otherwise, propertyMetadata.Model is likely already null.)
                ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[missingRequiredProperty];
                propertyMetadata.Model = null;

                // Execute validator (if any) to get custom error message.
                ModelValidator validator  = requiredValidators[missingRequiredProperty];
                bool           addedError = RunValidator(validator, bindingContext, propertyMetadata, modelStateKey);

                // Fall back to default message if HttpBindingBehaviorAttribute required this property or validator
                // (oddly) succeeded.
                if (!addedError)
                {
                    bindingContext.ModelState.AddModelError(modelStateKey,
                                                            Error.Format(SRResources.MissingRequiredMember, missingRequiredProperty));
                }
            }

            // for each property that was bound, call the setter, recording exceptions as necessary
            foreach (var entry in dto.Results)
            {
                ModelMetadata propertyMetadata = entry.Key;

                ComplexModelDtoResult dtoResult = entry.Value;
                if (dtoResult != null)
                {
                    SetProperty(actionContext, bindingContext, propertyMetadata, dtoResult, requiredValidators[propertyMetadata.PropertyName]);
                    bindingContext.ValidationNode.ChildNodes.Add(dtoResult.ValidationNode);
                }
            }
        }
コード例 #23
0
        /// <summary>
        /// Attempt to bind against the given ActionContext.
        /// </summary>
        /// <param name="actionContext">The action context.</param>
        /// <param name="bindingContext">The binding context.</param>
        /// <param name="binders">set of binders to use for binding</param>
        /// <returns>True if the bind was successful, else false.</returns>
        public static bool Bind(
            this HttpActionContext actionContext,
            ModelBindingContext bindingContext,
            IEnumerable <IModelBinder> binders
            )
        {
            if (actionContext == null)
            {
                throw Error.ArgumentNull("actionContext");
            }

            if (bindingContext == null)
            {
                throw Error.ArgumentNull("bindingContext");
            }

            // Protects against stack overflow for deeply nested model binding
            RuntimeHelpers.EnsureSufficientExecutionStack();

            Type modelType           = bindingContext.ModelType;
            HttpConfiguration config = actionContext.ControllerContext.Configuration;

            ModelBinderProvider providerFromAttr;

            if (ModelBindingHelper.TryGetProviderFromAttributes(modelType, out providerFromAttr))
            {
                IModelBinder binder = providerFromAttr.GetBinder(config, modelType);
                if (binder != null)
                {
                    return(binder.BindModel(actionContext, bindingContext));
                }
            }

            foreach (IModelBinder binder in binders)
            {
                if (binder != null)
                {
                    if (binder.BindModel(actionContext, bindingContext))
                    {
                        return(true);
                    }
                }
            }

            // Either we couldn't find a binder, or the binder couldn't bind. Distinction is not important.
            return(false);
        }
コード例 #24
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 static List <TElement> BindSimpleCollection(
            HttpActionContext actionContext,
            ModelBindingContext bindingContext,
            object rawValue,
            CultureInfo culture
            )
        {
            if (rawValue == null)
            {
                return(null); // nothing to do
            }

            List <TElement> boundCollection = new List <TElement>();

            object[] rawValueArray = ModelBindingHelper.RawValueToObjectArray(rawValue);
            foreach (object rawValueElement in rawValueArray)
            {
                ModelBindingContext innerBindingContext = new ModelBindingContext(bindingContext)
                {
                    ModelMetadata = actionContext
                                    .GetMetadataProvider()
                                    .GetMetadataForType(null, typeof(TElement)),
                    ModelName     = bindingContext.ModelName,
                    ValueProvider = new CompositeValueProvider
                    {
                        new ElementalValueProvider(
                            bindingContext.ModelName,
                            rawValueElement,
                            culture
                            ), // our temporary provider goes at the front of the list
                        bindingContext.ValueProvider
                    }
                };

                object boundValue = null;
                if (actionContext.Bind(innerBindingContext))
                {
                    boundValue = innerBindingContext.Model;
                    bindingContext.ValidationNode.ChildNodes.Add(
                        innerBindingContext.ValidationNode
                        );
                }
                boundCollection.Add(ModelBindingHelper.CastOrDefault <TElement>(boundValue));
            }

            return(boundCollection);
        }
コード例 #25
0
        private void ValidateProperties(HttpActionContext actionContext)
        {
            // Based off CompositeModelValidator.
            ModelStateDictionary modelState = actionContext.ModelState;

            // DevDiv Bugs #227802 - Caching problem in ModelMetadata requires us to manually regenerate
            // the ModelMetadata.
            object        model           = ModelMetadata.Model;
            ModelMetadata updatedMetadata = actionContext
                                            .GetMetadataProvider()
                                            .GetMetadataForType(() => model, ModelMetadata.ModelType);

            foreach (ModelMetadata propertyMetadata in updatedMetadata.Properties)
            {
                // Only want to add errors to ModelState if something doesn't already exist for the property node,
                // else we could end up with duplicate or irrelevant error messages.
                string propertyKeyRoot = ModelBindingHelper.CreatePropertyModelName(
                    ModelStateKey,
                    propertyMetadata.PropertyName
                    );

                if (modelState.IsValidField(propertyKeyRoot))
                {
                    foreach (
                        ModelValidator propertyValidator in actionContext.GetValidators(
                            propertyMetadata
                            )
                        )
                    {
                        foreach (
                            ModelValidationResult propertyResult in propertyValidator.Validate(
                                propertyMetadata,
                                model
                                )
                            )
                        {
                            string thisErrorKey = ModelBindingHelper.CreatePropertyModelName(
                                propertyKeyRoot,
                                propertyResult.MemberName
                                );
                            modelState.AddModelError(thisErrorKey, propertyResult.Message);
                        }
                    }
                }
            }
        }
コード例 #26
0
        public void GetPropertyName_NonParameterBasedExpression_Throws()
        {
            // Arrange
            var someUser = new User();

            // PropertyAccessor with a property name invalid as it originates from a variable accessor.
            Expression <Func <User, object> > expression = m => someUser.Address;

            // Act & Assert
            var ex = Assert.Throws <InvalidOperationException>(() =>
                                                               ModelBindingHelper.GetPropertyName(expression.Body));

            Assert.Equal(string.Format("The passed expression of expression node type '{0}' is invalid." +
                                       " Only simple member access expressions for model properties are supported.",
                                       expression.Body.NodeType),
                         ex.Message);
        }
コード例 #27
0
        public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            string keyFieldName   = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, "key");
            string valueFieldName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, "value");

            if (bindingContext.ValueProvider.ContainsPrefix(keyFieldName) && bindingContext.ValueProvider.ContainsPrefix(valueFieldName))
            {
                return(ModelBindingHelper.GetPossibleBinderInstance(bindingContext.ModelType, typeof(KeyValuePair <,>) /* supported model type */, typeof(KeyValuePairModelBinder <,>) /* binder type */));
            }
            else
            {
                // 'key' or 'value' missing
                return(null);
            }
        }
コード例 #28
0
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ValueProviderResult valueProviderResult = GetCompatibleValueProviderResult(bindingContext);

            if (valueProviderResult == null)
            {
                return(false); // conversion would have failed
            }

            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
            object model = valueProviderResult.RawValue;

            ModelBindingHelper.ReplaceEmptyStringWithNull(bindingContext.ModelMetadata, ref model);
            bindingContext.Model = model;

            return(true);
        }
コード例 #29
0
        private async Task <bool> TryUpdateModelAsync(
            object model,
            string prefix,
            ModelBindingTestContext testContext)
        {
            var valueProvider = await CompositeValueProvider.CreateAsync(testContext);

            return(await ModelBindingHelper.TryUpdateModelAsync(
                       model,
                       model.GetType(),
                       prefix,
                       testContext,
                       testContext.MetadataProvider,
                       TestModelBinderFactory.CreateDefault(),
                       valueProvider,
                       ModelBindingTestHelper.GetObjectValidator(testContext.MetadataProvider)));
        }
コード例 #30
0
        private void ValidateThis(HttpActionContext actionContext, ModelValidationNode parentNode)
        {
            ModelStateDictionary modelState = actionContext.ModelState;

            if (!modelState.IsValidField(ModelStateKey))
            {
                return; // short-circuit
            }

            // If 'this' 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)
            {
                string trueModelStateKey = ModelBindingHelper.CreatePropertyModelName(
                    ModelStateKey,
                    ModelMetadata.GetDisplayName()
                    );
                modelState.AddModelError(trueModelStateKey, SRResources.Validation_ValueNotFound);
                return;
            }

            _validators = actionContext.GetValidators(ModelMetadata);

            object container = TryConvertContainerToMetadataType(parentNode);

            // Optimize for the common case where the validators are in an array
            ModelValidator[] validators = _validators.AsArray();
            for (int i = 0; i < validators.Length; i++)
            {
                ModelValidator validator = validators[i];
                foreach (
                    ModelValidationResult validationResult in validator.Validate(
                        ModelMetadata,
                        container
                        )
                    )
                {
                    string trueModelStateKey = ModelBindingHelper.CreatePropertyModelName(
                        ModelStateKey,
                        validationResult.MemberName
                        );
                    modelState.AddModelError(trueModelStateKey, validationResult.Message);
                }
            }
        }