private static object ReadAsInternal(
            this FormDataCollection formData,
            Type type,
            string modelName,
            HttpActionContext actionContext
            )
        {
            Contract.Assert(formData != null);
            Contract.Assert(type != null);
            Contract.Assert(actionContext != null);

            IValueProvider      valueProvider  = formData.GetJQueryValueProvider();
            ModelBindingContext bindingContext = CreateModelBindingContext(
                actionContext,
                modelName ?? String.Empty,
                type,
                valueProvider
                );

            ModelBinderProvider modelBinderProvider = CreateModelBindingProvider(actionContext);

            IModelBinder modelBinder = modelBinderProvider.GetBinder(
                actionContext.ControllerContext.Configuration,
                type
                );
            bool haveResult = modelBinder.BindModel(actionContext, bindingContext);

            if (haveResult)
            {
                return(bindingContext.Model);
            }

            return(MediaTypeFormatter.GetDefaultValueForType(type));
        }
        /// <summary>
        /// Deserialize the form data to the given type, using model binding.
        /// </summary>
        /// <param name="formData">collection with parsed form url data</param>
        /// <param name="type">target type to read as</param>
        /// <param name="modelName">null or empty to read the entire form as a single object. This is common for body data.
        /// <param name="requiredMemberSelector">The <see cref="IRequiredMemberSelector"/> used to determine required members.</param>
        /// <param name="formatterLogger">The <see cref="IFormatterLogger"/> to log events to.</param>
        /// Or the name of a model to do a partial binding against the form data. This is common for extracting individual fields.</param>
        /// <returns>best attempt to bind the object. The best attempt may be null.</returns>
        public static object ReadAs(this FormDataCollection formData, Type type, string modelName, IRequiredMemberSelector requiredMemberSelector, IFormatterLogger formatterLogger)
        {
            if (formData == null)
            {
                throw Error.ArgumentNull("formData");
            }
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }

            if (modelName == null)
            {
                modelName = string.Empty;
            }

            using (HttpConfiguration config = new HttpConfiguration())
            {
                bool validateRequiredMembers = requiredMemberSelector != null && formatterLogger != null;
                if (validateRequiredMembers)
                {
                    // Set a ModelValidatorProvider that understands the IRequiredMemberSelector
                    config.Services.Replace(typeof(ModelValidatorProvider), new RequiredMemberModelValidatorProvider(requiredMemberSelector));
                }

                // Looks like HttpActionContext is just a way of getting to the config, which we really
                // just need to get a list of modelbinderPRoviders for composition.
                HttpControllerContext controllerContext = new HttpControllerContext()
                {
                    Configuration = config
                };
                HttpActionContext actionContext = new HttpActionContext {
                    ControllerContext = controllerContext
                };

                ModelMetadataProvider metadataProvider = config.Services.GetModelMetadataProvider();

                // Create default over config
                IEnumerable <ModelBinderProvider> providers = config.Services.GetModelBinderProviders();
                ModelBinderProvider modelBinderProvider     = new CompositeModelBinderProvider(providers);

                IValueProvider vp = formData.GetJQueryValueProvider();

                ModelBindingContext ctx = new ModelBindingContext()
                {
                    ModelName             = modelName,
                    FallbackToEmptyPrefix = false,
                    ModelMetadata         = metadataProvider.GetMetadataForType(null, type),
                    ModelState            = actionContext.ModelState,
                    ValueProvider         = vp
                };

                IModelBinder binder = modelBinderProvider.GetBinder(actionContext, ctx);

                bool haveResult = binder.BindModel(actionContext, ctx);

                // Log model binding errors
                if (validateRequiredMembers)
                {
                    Contract.Assert(formatterLogger != null);
                    foreach (KeyValuePair <string, ModelState> modelStatePair in actionContext.ModelState)
                    {
                        foreach (ModelError modelError in modelStatePair.Value.Errors)
                        {
                            formatterLogger.LogError(modelStatePair.Key, modelError.ErrorMessage);
                        }
                    }
                }

                if (haveResult)
                {
                    return(ctx.Model);
                }
                return(null);
            }
        }
示例#3
0
        /// <summary>
        /// Deserialize the form data to the given type, using model binding.
        /// </summary>
        /// <param name="formData">collection with parsed form url data</param>
        /// <param name="type">target type to read as</param>
        /// <param name="modelName">null or empty to read the entire form as a single object. This is common for body data.
        /// <param name="requiredMemberSelector">The <see cref="IRequiredMemberSelector"/> used to determine required members.</param>
        /// <param name="formatterLogger">The <see cref="IFormatterLogger"/> to log events to.</param>
        /// Or the name of a model to do a partial binding against the form data. This is common for extracting individual fields.</param>
        /// <returns>best attempt to bind the object. The best attempt may be null.</returns>
        public static object ReadAs(this FormDataCollection formData, Type type, string modelName, IRequiredMemberSelector requiredMemberSelector, IFormatterLogger formatterLogger)
        {
            if (formData == null)
            {
                throw Error.ArgumentNull("formData");
            }
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }

            if (modelName == null)
            {
                modelName = String.Empty;
            }

            using (HttpConfiguration config = new HttpConfiguration())
            {
                bool validateRequiredMembers = requiredMemberSelector != null && formatterLogger != null;
                if (validateRequiredMembers)
                {
                    // Set a ModelValidatorProvider that understands the IRequiredMemberSelector
                    config.Services.Replace(typeof(ModelValidatorProvider), new RequiredMemberModelValidatorProvider(requiredMemberSelector));
                }

                // Looks like HttpActionContext is just a way of getting to the config, which we really
                // just need to get a list of modelbinderPRoviders for composition.
                HttpActionContext actionContext = CreateActionContextForModelBinding(config);

                IValueProvider      vp  = formData.GetJQueryValueProvider();
                ModelBindingContext ctx = CreateModelBindingContext(actionContext, modelName, type, vp);

                ModelBinderProvider modelBinderProvider = CreateModelBindingProvider(actionContext);

                IModelBinder binder     = modelBinderProvider.GetBinder(config, type);
                bool         haveResult = binder.BindModel(actionContext, ctx);

                // Log model binding errors
                if (formatterLogger != null)
                {
                    foreach (KeyValuePair <string, ModelState> modelStatePair in actionContext.ModelState)
                    {
                        foreach (ModelError modelError in modelStatePair.Value.Errors)
                        {
                            if (modelError.Exception != null)
                            {
                                formatterLogger.LogError(modelStatePair.Key, modelError.Exception);
                            }
                            else
                            {
                                formatterLogger.LogError(modelStatePair.Key, modelError.ErrorMessage);
                            }
                        }
                    }
                }

                if (haveResult)
                {
                    return(ctx.Model);
                }
                return(MediaTypeFormatter.GetDefaultValueForType(type));
            }
        }