// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.Contracts; using System.Linq; using System.Runtime.CompilerServices; using System.Web.Http.Metadata; using System.Web.Http.ModelBinding; using System.Web.Http.Validation; namespace System.Web.Http.Controllers { /// /// Extension methods for . /// [EditorBrowsable(EditorBrowsableState.Never)] public static class HttpActionContextExtensions { /// /// Gets the instance for a given . /// /// The context. /// An instance. public static ModelMetadataProvider GetMetadataProvider(this HttpActionContext actionContext) { if (actionContext == null) { throw Error.ArgumentNull("actionContext"); } return actionContext.ControllerContext.Configuration.Services.GetModelMetadataProvider(); } /// /// Gets the collection of registered instances. /// /// The context. /// A collection of instances. public static IEnumerable GetValidatorProviders(this HttpActionContext actionContext) { if (actionContext == null) { throw Error.ArgumentNull("actionContext"); } return actionContext.ControllerContext.Configuration.Services.GetModelValidatorProviders(); } /// /// Gets the collection of registered instances. /// /// The context. /// The metadata. /// A collection of registered instances. public static IEnumerable GetValidators(this HttpActionContext actionContext, ModelMetadata metadata) { if (actionContext == null) { throw Error.ArgumentNull("actionContext"); } IModelValidatorCache validatorCache = actionContext.GetValidatorCache(); return actionContext.GetValidators(metadata, validatorCache); } internal static IEnumerable GetValidators(this HttpActionContext actionContext, ModelMetadata metadata, IModelValidatorCache validatorCache) { if (validatorCache == null) { // slow path: there is no validator cache on the configuration return metadata.GetValidators(actionContext.GetValidatorProviders()); } else { return validatorCache.GetValidators(metadata); } } internal static IModelValidatorCache GetValidatorCache(this HttpActionContext actionContext) { Contract.Assert(actionContext != null); HttpConfiguration configuration = actionContext.ControllerContext.Configuration; return configuration.Services.GetModelValidatorCache(); } public static bool TryBindStrongModel(this HttpActionContext actionContext, ModelBindingContext parentBindingContext, string propertyName, ModelMetadataProvider metadataProvider, out TModel model) { if (actionContext == null) { throw Error.ArgumentNull("actionContext"); } ModelBindingContext propertyBindingContext = new ModelBindingContext(parentBindingContext) { ModelMetadata = metadataProvider.GetMetadataForType(null, typeof(TModel)), ModelName = ModelBindingHelper.CreatePropertyModelName(parentBindingContext.ModelName, propertyName) }; if (actionContext.Bind(propertyBindingContext)) { object untypedModel = propertyBindingContext.Model; model = ModelBindingHelper.CastOrDefault(untypedModel); parentBindingContext.ValidationNode.ChildNodes.Add(propertyBindingContext.ValidationNode); return true; } model = default(TModel); return false; } // Pulls binders from the config public static bool Bind(this HttpActionContext actionContext, ModelBindingContext bindingContext) { Type modelType = bindingContext.ModelType; HttpConfiguration config = actionContext.ControllerContext.Configuration; IEnumerable binders = from provider in config.Services.GetModelBinderProviders() select provider.GetBinder(config, modelType); return Bind(actionContext, bindingContext, binders); } /// /// Attempt to bind against the given ActionContext. /// /// The action context. /// The binding context. /// set of binders to use for binding /// True if the bind was successful, else false. public static bool Bind(this HttpActionContext actionContext, ModelBindingContext bindingContext, IEnumerable 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; } } }