How to map a 1 or 0 in an ASP.Net MVC route segment into a Boolean action method input parameter
Asked Answered
P

4

9

We have some PHP and Javascript apps that call into some ASP.NET MVC endpoints. Let's say we have this endpoint:

public ActionResult DoSomething(bool flag)
{

}

I want it to match the value for flag whether I pass in an integer of 1 or 0, or pass in a string of "true" or "false". What part of the framework do I need to implement in order to match that up?

Pedicle answered 22/2, 2013 at 15:37 Comment(1)
you want to create custom routes. 2 or 3 of them. Add several example URL's to work with. Also explain if these end points will vary at all from your standard routes. If they do (start with something like bool) that will be better.Larceny
C
9

The best way to do this is using a custom value provider. While you can do this using a complete custom model binder, that is overkill based on your requirements, and it is much easier simply to implement a custom value provider.

For some guidance on when you use a custom model binder and when to use a custom value provider, see here and here.

You can just create a custom value provider to handle route values having a key of "flag" and handle the int to bool conversion in the value provider. The code to do this looks something like this:

public class IntToBoolValueProvider : IValueProvider
{
    public IntToBoolValueProvider(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        this._context = context;
    }
    public bool ContainsPrefix(string prefix)
    {
        return prefix.ToLower().IndexOf("flag") > -1;
    }
    public ValueProviderResult GetValue(string key)
    {
        if (ContainsPrefix(key))
        {
            int value = 0;
            int.TryParse(_context.RouteData.Values[key].ToString(), out value);
            bool result = value > 0;
            return new ValueProviderResult(result, result.ToString(), CultureInfo.InvariantCulture);
        }
        else
        {
            return null;
        }
    }
    ControllerContext _context;
}

public class IntToBoolValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        return new IntToBoolValueProvider(controllerContext);
    }
}

In the value provider, you implement the ContainsPrefix method to return true for the route value keys you are interested in, in this case the key "flag". In the GetValue flag, you convert the value of the "flag" route data entry to an int, and then to a boolean, depending if the int is greater than zero. For all other route data keys that are not "flag", you just return null, which tells the MVC framework to ignore this ValueProvider and move on to other value providers.

To wire this up, you need to implement a subclass of ValueProviderFactory which creates the custom IntToBoolValueProvider provider. Also, you need to register this factory with the MVC framework. You do this in global.asax using the static ValueProviderFactories class:

protected void Application_Start()
{
    ValueProviderFactories.Factories.Insert(0, new IntToBoolValueProviderFactory());
}

If you then have a route set up as follows:

routes.MapRoute("", "{controller}/foo/{flag}", new { action = "Foo" });

this route will direct requests to

http://localhost:60286/Home/Foo/{flag}

to the action method

    public ActionResult Foo(bool flag)
    {
        //Implement action method
        return View("Index");
    }

When the {flag} segment is greater than 0, the bool flag input parameter will be true, and when it is zero, the flag parameter will be false.

More on MVC custom value providers can be found here.

Cystolith answered 22/2, 2013 at 16:12 Comment(0)
S
0

What part of the framework do I need to implement in order to match that up?

A custom model binder.

Symphonious answered 22/2, 2013 at 15:44 Comment(0)
S
0

You could use a custom model binder, as found in this SO question ASP.NET MVC controller actions with custom parameter conversion?

Now if you wanted to do this globally so you didn't have to set an attribute on every bool that might get a 0/1 instead of true/false, then you can extend the default model binder to understand 0 or 1 as false or true by overriding the default model binder, as found in this SO question Change the default model binder in asp.net MVC

Some combination of these two should get you what you want.

Strobotron answered 22/2, 2013 at 15:45 Comment(0)
C
0

This is a workaround but it's sample in ultimate instance if you don't want modify or create a model binder.

public ActionResult DoSomething(string flag)
{

      if(flag.Equals("true") || flag.Equals(1)) {
            //condition true, any else false
      }


}
Cowcatcher answered 12/10, 2020 at 1:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.