Example #1
0
 // selects the v3.5 (legacy) or v4 HTML encoder
 private static HtmlEncoder GetHtmlEncoder()
 {
     return(TypeHelpers.CreateDelegate <HtmlEncoder>(TypeHelpers.SystemWebAssembly, "System.Web.HttpUtility", "HtmlEncode", null)
            ?? EncodeLegacy);
 }
        protected virtual void SetProperty(
            ControllerContext controllerContext,
            ModelBindingContext bindingContext,
            PropertyDescriptor propertyDescriptor,
            object value
            )
        {
            ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[
                propertyDescriptor.Name
                                             ];

            propertyMetadata.Model = value;
            string modelStateKey = CreateSubPropertyName(
                bindingContext.ModelName,
                propertyMetadata.PropertyName
                );

            // If the value is null, and the validation system can find a Required validator for
            // us, we'd prefer to run it before we attempt to set the value; otherwise, property
            // setters which throw on null (f.e., Entity Framework properties which are backed by
            // non-nullable strings in the DB) will get their error message in ahead of us.
            //
            // We are effectively using the special validator -- Required -- as a helper to the
            // binding system, which is why this code is here instead of in the Validating/Validated
            // methods, which are really the old-school validation hooks.
            if (value == null && bindingContext.ModelState.IsValidField(modelStateKey))
            {
                ModelValidator requiredValidator = ModelValidatorProviders.Providers
                                                   .GetValidators(propertyMetadata, controllerContext)
                                                   .Where(v => v.IsRequired)
                                                   .FirstOrDefault();
                if (requiredValidator != null)
                {
                    foreach (
                        ModelValidationResult validationResult in requiredValidator.Validate(
                            bindingContext.Model
                            )
                        )
                    {
                        bindingContext.ModelState.AddModelError(
                            modelStateKey,
                            validationResult.Message
                            );
                    }
                }
            }

            bool isNullValueOnNonNullableType =
                value == null && !TypeHelpers.TypeAllowsNullValue(propertyDescriptor.PropertyType);

            // Try to set a value into the property unless we know it will fail (read-only
            // properties and null values with non-nullable types)
            if (!propertyDescriptor.IsReadOnly && !isNullValueOnNonNullableType)
            {
                try
                {
                    propertyDescriptor.SetValue(bindingContext.Model, value);
                }
                catch (Exception ex)
                {
                    // Only add if we're not already invalid
                    if (bindingContext.ModelState.IsValidField(modelStateKey))
                    {
                        bindingContext.ModelState.AddModelError(modelStateKey, ex);
                    }
                }
            }

            // Last chance for an error on null values with non-nullable types, we'll use
            // the default "A value is required." message.
            if (
                isNullValueOnNonNullableType &&
                bindingContext.ModelState.IsValidField(modelStateKey)
                )
            {
                bindingContext.ModelState.AddModelError(
                    modelStateKey,
                    GetValueRequiredResource(controllerContext)
                    );
            }
        }
Example #3
0
        internal object BindComplexModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            object model     = bindingContext.Model;
            Type   modelType = bindingContext.ModelType;

            // if we're being asked to create an array, create a list instead, then coerce to an array after the list is created
            if (model == null && modelType.IsArray)
            {
                Type   elementType = modelType.GetElementType();
                Type   listType    = typeof(List <>).MakeGenericType(elementType);
                object collection  = CreateModel(controllerContext, bindingContext, listType);

                ModelBindingContext arrayBindingContext = new ModelBindingContext()
                {
                    ModelMetadata  = ModelMetadataProviders.Current.GetMetadataForType(() => collection, listType),
                    ModelName      = bindingContext.ModelName,
                    ModelState     = bindingContext.ModelState,
                    PropertyFilter = bindingContext.PropertyFilter,
                    ValueProvider  = bindingContext.ValueProvider
                };
                IList list = (IList)UpdateCollection(controllerContext, arrayBindingContext, elementType);

                if (list == null)
                {
                    return(null);
                }

                Array array = Array.CreateInstance(elementType, list.Count);
                list.CopyTo(array, 0);
                return(array);
            }

            if (model == null)
            {
                model = CreateModel(controllerContext, bindingContext, modelType);
            }

            // special-case IDictionary<,> and ICollection<>
            Type dictionaryType = TypeHelpers.ExtractGenericInterface(modelType, typeof(IDictionary <,>));

            if (dictionaryType != null)
            {
                Type[] genericArguments = dictionaryType.GetGenericArguments();
                Type   keyType          = genericArguments[0];
                Type   valueType        = genericArguments[1];

                ModelBindingContext dictionaryBindingContext = new ModelBindingContext()
                {
                    ModelMetadata  = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType),
                    ModelName      = bindingContext.ModelName,
                    ModelState     = bindingContext.ModelState,
                    PropertyFilter = bindingContext.PropertyFilter,
                    ValueProvider  = bindingContext.ValueProvider
                };
                object dictionary = UpdateDictionary(controllerContext, dictionaryBindingContext, keyType, valueType);
                return(dictionary);
            }

            Type enumerableType = TypeHelpers.ExtractGenericInterface(modelType, typeof(IEnumerable <>));

            if (enumerableType != null)
            {
                Type elementType = enumerableType.GetGenericArguments()[0];

                Type collectionType = typeof(ICollection <>).MakeGenericType(elementType);
                if (collectionType.IsInstanceOfType(model))
                {
                    ModelBindingContext collectionBindingContext = new ModelBindingContext()
                    {
                        ModelMetadata  = ModelMetadataProviders.Current.GetMetadataForType(() => model, modelType),
                        ModelName      = bindingContext.ModelName,
                        ModelState     = bindingContext.ModelState,
                        PropertyFilter = bindingContext.PropertyFilter,
                        ValueProvider  = bindingContext.ValueProvider
                    };
                    object collection = UpdateCollection(controllerContext, collectionBindingContext, elementType);
                    return(collection);
                }
            }

            // otherwise, just update the properties on the complex type
            BindComplexElementalModel(controllerContext, bindingContext, model);
            return(model);
        }
        internal object BindSimpleModel(
            ControllerContext controllerContext,
            ModelBindingContext bindingContext,
            ValueProviderResult valueProviderResult
            )
        {
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

            // if the value provider returns an instance of the requested data type, we can just short-circuit
            // the evaluation and return that instance
            if (bindingContext.ModelType.IsInstanceOfType(valueProviderResult.RawValue))
            {
                return(valueProviderResult.RawValue);
            }

            // since a string is an IEnumerable<char>, we want it to skip the two checks immediately following
            if (bindingContext.ModelType != typeof(string))
            {
                // conversion results in 3 cases, as below
                if (bindingContext.ModelType.IsArray)
                {
                    // case 1: user asked for an array
                    // ValueProviderResult.ConvertTo() understands array types, so pass in the array type directly
                    object modelArray = ConvertProviderResult(
                        bindingContext.ModelState,
                        bindingContext.ModelName,
                        valueProviderResult,
                        bindingContext.ModelType
                        );
                    return(modelArray);
                }

                Type enumerableType = TypeHelpers.ExtractGenericInterface(
                    bindingContext.ModelType,
                    typeof(IEnumerable <>)
                    );
                if (enumerableType != null)
                {
                    // case 2: user asked for a collection rather than an array
                    // need to call ConvertTo() on the array type, then copy the array to the collection
                    object modelCollection = CreateModel(
                        controllerContext,
                        bindingContext,
                        bindingContext.ModelType
                        );
                    Type   elementType = enumerableType.GetGenericArguments()[0];
                    Type   arrayType   = elementType.MakeArrayType();
                    object modelArray  = ConvertProviderResult(
                        bindingContext.ModelState,
                        bindingContext.ModelName,
                        valueProviderResult,
                        arrayType
                        );

                    Type collectionType = typeof(ICollection <>).MakeGenericType(elementType);
                    if (collectionType.IsInstanceOfType(modelCollection))
                    {
                        CollectionHelpers.ReplaceCollection(
                            elementType,
                            modelCollection,
                            modelArray
                            );
                    }
                    return(modelCollection);
                }
            }

            // case 3: user asked for an individual element
            object model = ConvertProviderResult(
                bindingContext.ModelState,
                bindingContext.ModelName,
                valueProviderResult,
                bindingContext.ModelType
                );

            return(model);
        }