Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Boolean Parameter Binding

I have a WebApi method, like this one:

public string Get([FromUri] SampleInput input)
{
    //do stuff with the input...
    return "ok";
}

The input is defined like this:

public class SampleInput
{
    // ...other fields
    public bool IsAwesome { get; set; }
}

As it is, it works OK: if I pass &isAwesome=true in the query string, the parameter is initializes with the value true.

My problem is that I'd like to accept both &isAwesome=true and &isAwesome=1 as true values. Currently, the second version will result in IsAwesome being false in the input model.


What I tried, after reading the various blog posts on the subject, was to define an HttpParameterBinding:

public class BooleanNumericParameterBinding : HttpParameterBinding
{
    private static readonly HashSet<string> TrueValues =
        new HashSet<string>(new[] { "true", "1" }, StringComparer.InvariantCultureIgnoreCase);

    public BooleanNumericParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor)
    {
    }

    public override Task ExecuteBindingAsync(
        ModelMetadataProvider metadataProvider, 
        HttpActionContext actionContext,
        CancellationToken cancellationToken)
    {
        var routeValues = actionContext.ControllerContext.RouteData.Values;

        var value = (routeValues[Descriptor.ParameterName] ?? 0).ToString();

        return Task.FromResult(TrueValues.Contains(value));
    }
}

... and register it in Global.asax.cs, using:

var pb = GlobalConfiguration.Configuration.ParameterBindingRules;
pb.Add(typeof(bool), p => new BooleanNumericParameterBinding(p));

and

var pb = GlobalConfiguration.Configuration.ParameterBindingRules;
pb.Insert(0, typeof(bool), p => new BooleanNumericParameterBinding(p));

None of these worked. My custom HttpParameterBinding is not being called and I still get the value 1 translated to false.

How can I configure WebAPI to accept the value 1 as true for Booleans?

Edit: The example I presented is intentionally simplified. I have a lot of input models in my application and they contain many boolean fields that I would like to be handled in the manner described above. If there was just this one field, I would not have resorted to such complex mechanisms.

like image 700
Cristian Lupascu Avatar asked Oct 14 '14 09:10

Cristian Lupascu


1 Answers

Looks like decorating the parameter with the FromUriAttribute just skips the parameter binding rules altogether. I made a simple test replacing the SampleInput input parameter with a simple bool:

public string Get([FromUri] bool IsAwesome)
{
    //do stuff with the input...
    return "ok";
}

and the boolean rule is still not getting called (IsAwesome is coming as null when you call &isAwesome=1). As soon as you remove the FromUri attribute:

public string Get(bool IsAwesome)
{
    //do stuff with the input...
    return "ok";
}

the rule gets called and the parameter correctly bound. The FromUriAttribute class is sealed, so I think you're pretty much screwed - well, you can always reimplement it and include your alternate boolean binding logic ^_^.

like image 166
Samuele Avatar answered Sep 21 '22 21:09

Samuele