147

Our company is developing an API for our products and we are thinking about using ASP.NET MVC. While designing our API, we decided to use calls like the one below for the user to request information from the API in XML format:

http://ws.audioscrobbler.com/2.0/?method=artist.getimages&artist=cher&api_key=b25b959554ed76058ac220b7b2e0a026

As you can see, multiple parameters are passed (i.e. artist and api_key). In ASP.NET MVC, artist would be the controller, getImages the action, but how would I pass multiple parameters to the action?

Is this even possible using the format above?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
CodingWithoutComments
  • 35,598
  • 21
  • 73
  • 86

3 Answers3

295

Parameters are directly supported in MVC by simply adding parameters onto your action methods. Given an action like the following:

public ActionResult GetImages(string artistName, string apiKey)

MVC will auto-populate the parameters when given a URL like:

/Artist/GetImages/?artistName=cher&apiKey=XXX

One additional special case is parameters named "id". Any parameter named ID can be put into the path rather than the querystring, so something like:

public ActionResult GetImages(string id, string apiKey)

would be populated correctly with a URL like the following:

/Artist/GetImages/cher?apiKey=XXX

In addition, if you have more complicated scenarios, you can customize the routing rules that MVC uses to locate an action. Your global.asax file contains routing rules that can be customized. By default the rule looks like this:

routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );

If you wanted to support a url like

/Artist/GetImages/cher/api-key

you could add a route like:

routes.MapRoute(
            "ArtistImages",                                              // Route name
            "{controller}/{action}/{artistName}/{apikey}",                           // URL with parameters
            new { controller = "Home", action = "Index", artistName = "", apikey = "" }  // Parameter defaults
        );

and a method like the first example above.

Ryan Brunner
  • 14,723
  • 1
  • 36
  • 52
  • 2
    I'm working with .NET 4 and MVC. I can only pass one parameter in the path. This URL {controller}/{action}/{artistName}/{apikey} doesn't map to 2 parameters for me but simply triggers a 404 error. As far as I can tell you can only pass 1 parameter in the path. What am I doing wrong? – DavidHyogo Feb 12 '13 at 14:22
  • 2
    @DavidHyogo - I was experiencing the same issue. For whatever reason, even though I specified the default action, I had to actually put the action I wanted in my html link, not just the controller, and parameters. – Shaggy13spe Feb 24 '13 at 18:26
  • 7
    @DavidHyogo: I had the same issue and discovered that your route template parameters must exactly match the action method parameter names e.g. for route defined as {controller}/{action}/{artistName}/{apikey} the action method should have the signature public ActionResult MyMethod(string artistName, string apikey) – Sudhanshu Mishra Jun 26 '13 at 06:52
  • 8
    Also, make sure your URL isn't getting caught by the default route before it reaches your custom one. It will use the first match based on how you defined them. In my case, I was trying to use the route "MyController/{year}/{month}" for the default of Index, but the route {controller}/{action}/{id} was matching my URL (MyController/2015/04), so I was getting a 404 because no action with the name 2015 existed. Moving my custom route to the top fixed the problem. – Sam Sep 14 '15 at 15:59
  • The parameters name in the routeconfig didn't match my Action signature, that's why it wasn't working, I followed the steps described by @dotnetguy and it worked – pepitomb Oct 21 '16 at 21:36
  • Beware that in this URL-based approach, any dots/periods in your parameter values will cause your URL to get picked up by the static file URL manager and your API will not work. This is a known problem with all the ASP.NET MVC routing approaches and there is no properly performing workaround (IMHO). More discussion here: http://stackoverflow.com/questions/20998816/dot-character-in-mvc-web-api-2-for-request-such-as-api-people-staff-45287 Note that a lot of the fixes are specific to a version of MVC, so what works for one may not work on yours. – theta-fish Feb 22 '17 at 17:27
  • Your last example with custom url is exactly what i needed to do (e.g. /Customers/Edit/1 instead of Customers/Edit?id=1), thanks a lot – Dimitris Thomas Mar 19 '21 at 17:19
28

Starting with MVC 5, you can also use Attribute Routing to move the URL parameter configuration to your controllers.

A detailed discussion is available here: http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx

Summary:

First you enable attribute routing

 public class RouteConfig 
 {
     public static void RegisterRoutes(RouteCollection routes)
     {
         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

         routes.MapMvcAttributeRoutes();
     } 
 }

Then you can use attributes to define parameters and optionally data types

public class BooksController : Controller
{
    // eg: /books
    // eg: /books/1430210079
    [Route("books/{isbn?}")]
    public ActionResult View(string isbn)
Bernard Vander Beken
  • 4,848
  • 5
  • 54
  • 76
23

You can pass arbitrary parameters through the query string, but you can also set up custom routes to handle it in a RESTful way:

http://ws.audioscrobbler.com/2.0/?method=artist.getimages&artist=cher&
                                  api_key=b25b959554ed76058ac220b7b2e0a026

That could be:

routes.MapRoute(
    "ArtistsImages",
    "{ws}/artists/{artist}/{action}/{*apikey}",
    new { ws = "2.0", controller="artists" artist = "", action="", apikey="" }
    );

So if someone used the following route:

ws.audioscrobbler.com/2.0/artists/cher/images/b25b959554ed76058ac220b7b2e0a026/

It would take them to the same place your example querystring did.

The above is just an example, and doesn't apply the business rules and constraints you'd have to set up to make sure people didn't 'hack' the URL.

George Stocker
  • 57,289
  • 29
  • 176
  • 237