// 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) ); } }
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); }