Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asp.net mvc - Route for string or int (i.e. /type/23 or /type/hats)

I have the following case where I want to accept the following routs

 '/type/view/23' or '/type/view/hats'

where 23 is the Id for hats.

The controller looks something like this:

public class TypeController
{ 
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult View(int id)
    {
      ...
    }
}

Now if they pass in 23 no problems. If they pass in hats, I have some work to do. Now I was wondering in this case would I translate hats to 23 by using an ActionFilter that looks to see if the value passed in as the id is an int (if so check that it exists in the database) or if it is a string looks up the database for what the id of the string that has been passed in is. In either case if a match is not found I would want redirect the user to a different action.

Firstly is the approach I have named correct, secondly is it posible to do a redirect from within an ActionFilter.

Cheers Anthony

like image 580
vdh_ant Avatar asked Oct 14 '22 15:10

vdh_ant


1 Answers

Change your signature to accept a string. Then check if the value of id is an int. If it is, then lookup by id, if not lookup by name. If you don't find a match, then do your redirect.

public class TypeController
{ 
    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult View(string id)
    {
       Product product = null;
       int productID = -1;
       if (int.TryParse( id, out productID))
       {
           product = db.Products
                       .Where( p => p.ID == productID )
                       .SingleOrDefault();
       }
       else
       {
           product = db.Products
                       .Where( p => p.Name == id )
                       .SingleOrDefault();
       }

       if (product == null)
       {
           return RedirectToAction( "Error" );
       }
       ...
    }
}

The reason that I would do this is that in order to know what controller/actions to apply, the framework is going to look for one that matches the signature of the route data that's passed in. If you don't have a signature that matches -- in this case one that takes a string -- you'll get an exception before any of your filters are invoked. Unfortunately, I don't think you can have one that takes a string and another that takes an int -- in that case the framework won't be able to tell which one should match if a single parameter is passed, at least if it's a number, that is. By making it a string parameter and handling the translation yourself, you allow the framework to do its work and you get the behavior you want -- no filter needed.

like image 151
tvanfosson Avatar answered Oct 18 '22 23:10

tvanfosson