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