Search code examples
http-headerscastle-windsorglobal-asaxasp.net-web-api-routinghttpconfiguration

Which HttpConfiguration object do I need to access to create a custom HttpParameterBinding?


In this post, Mike Wasson states:

"Besides ParameterBindingAttribute, there is another hook for adding a custom HttpParameterBinding. On the HttpConfiguration object"

But I have three HttpConfiguration objects in my Web API app, namely:

public static void Register(HttpConfiguration config, IWindsorContainer container) <-- in WebApiConfig.cs
private static void MapRoutes(HttpConfiguration config) <-- ""
public static void ConfigureWindsor(HttpConfiguration configuration) <-- in Global.asax.cs

Which of these (config, config, or configuration) should I use (if any)?

UPDATE

I tried this, with a breakpoint on the "if" line:

public static void ConfigureWindsor(HttpConfiguration configuration)
{
    _container = new WindsorContainer();
    _container.Install(FromAssembly.This());
    _container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
    var dependencyResolver = new WindsorDependencyResolver(_container);
    configuration.DependencyResolver = dependencyResolver;

    if (configuration.Properties.Values.Count > 0) // <-- I put a Casey Jones here
    {
        object o = configuration.Properties.Values.ElementAt(configuration.Properties.Values.Count - 1);
        string s = o.ToString();
    }
}

...but I only hit that spot once, on the server starting up, but not when the client sent a request to it...there must be some event that gets fired when a server passes a request where the incoming URL can be examined...no?


Solution

  • Usually you do have only one instance of HttpConfiguration which is the one you get from GlobalConfiguration.Configuration.

    Said so, that's how I plugged custom binders

    In global.asax

    var binderMappings = new Dictionary<Type, Type>
        {
            {typeof(YourModelType), typeof(YourModelTypeBinder)},
            //....
        };
    
    config.Services.Add(
        typeof(ModelBinderProvider),
        new WindsorModelBinderProvider(container, binderMappings));
    

    WindsorModelBinderProvider

    public class WindsorModelBinderProvider : ModelBinderProvider
    {
        private readonly IWindsorContainer _container;
        private readonly IDictionary<Type, Type> _binderMappings;
    
        public WindsorModelBinderProvider(IWindsorContainer container, IDictionary<Type, Type> binderMappings)
        {
            _container = container;
            _binderMappings = binderMappings;
        }
    
        public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
        {
            IModelBinder binder = null;
            if (_binderMappings.ContainsKey(modelType))
            {
                binder = _container.Resolve(_binderMappings[modelType]) as IModelBinder;
    
                if (binder == null)
                {
                    throw new ComponentNotFoundException(modelType);
                }
            }
    
            return binder;
        }
    }   
    

    YourModelTypeBinder

    public class YourModelTypeBinder : IModelBinder
    {
        public YourModelTypeBinder(IYourServiceToLoadYourModelType service)
        {
            //...
        }
    
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            bindingContext.Model = YourCustomCodeToLoadYourModelTypeUsingTheConstructorDependecies(actionContext.Request);
            return true;
        }
    
        private YourModelType YourCustomCodeToLoadYourModelTypeUsingTheConstructorDependecies(HttpRequestMessage requestMessage)
        {
            ...
        }
    }
    

    YourModelTypeBinder will be resolved by the container(see WindsorModelBinderProvider), so you need to registered it first.

    After all that plumbing, your controller may have a parameter, among others, as following

    [ModelBinder]YourModelType user