Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.net MVC routing with optional first parameter

I need to provide following functionality for one of the web sites.

http://www.example.com/[sponsor]/{controller}/{action}

Depending on the [sponsor], the web page has to be customized.

I tried combination of registering the routes with Application_Start and Session_Start but not able to get it working.

public static void RegisterRoutes(RouteCollection routes, string sponsor)
{
        if (routes[sponsor] == null)
    {
      routes.MapRoute(
     sponsor, // Route name
     sponsor + "/{controller}/{action}/{id}", // URL with parameters
     new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
     );
    }
}

Also, the default behavior without [sponsor] should also function. Can someone please let me know if it is technically feasible to have an optional first parameter in the MVC3 URL. If yes, please share the implementation. Thank you.


Updated Code After making the changes as suggested by Sergey Kudriavtsev, the code works when value is given. If name is not provided then MVC does not route to the controller/action.

Note that this works only for the home controller (both and non-sponsor). For other controllers/actions, even when sponsor parameter is specified it is not routing.

Please suggest what has to be modified.

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapRoute(
             "SponsorRoute",
             "{sponsor}/{controller}/{action}/{id}", // URL with parameters
             new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapRoute(
            "NonSponsorRoute",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor = string.Empty }
        );
    }

Action Method

public ActionResult Index(string sponsor)
    {
    }
like image 945
Sandeep G B Avatar asked Nov 29 '11 12:11

Sandeep G B


People also ask

How to make route parameter optional in MVC?

We can make a route parameter optional by adding “?” to it. The only gimmick is while declaring a route parameter as optional, we must specify a consequent default value for it: [HttpGet("GetById/{id?}")] In this case, we assign 1 as a default value for the id parameter in the GetById action method.

What is attribute routing in ASP net Web API 2. 0?

Routing is how Web API matches a URI to an action. Web API 2 supports a new type of routing, called attribute routing. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web API.

Which method is generally used for registering Web API routes?

Attribute routing is supported in Web API 2. As the name implies, attribute routing uses [Route()] attribute to define routes. The Route attribute can be applied on any controller or action method. In order to use attribute routing with Web API, it must be enabled in WebApiConfig by calling config.


1 Answers

In your case sponsor should not be treated as a constant part of URL, but as a variable part.

In Global.asax:

public static void RegisterRoutes(RouteCollection routes)
{
...
     routes.MapRoute(
     "SponsorRoute",
     "{sponsor}/{controller}/{action}/{id}", // URL with parameters
     new { controller = "Home", action = "Index", id = UrlParameter.Optional }
     );
     routes.MapRoute(
     "NonSponsorRoute",
     "{controller}/{action}/{id}",
     new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
     );

...
}

In your controllers, for example, HomeController.cs:

namespace YourWebApp.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index(string sponsor)
        {
            // Here you can do any pre-processing depending on sponsor value, including redirects etc.
        }
        ...
    }
}

Note that type of this parameter will always be System.String and the name of route template component {sponsor} must exactly match the name of action parameter string sponsor in your controllers.

UPD: Added second route for non-sponsor case.

Please note that such setup will complicate your logic, because you might confuse different urls, for example URL

http://www.example.com/a/b/c

could be matched by both routes: first one will have sponsor=a, controller=b and action=c; second one will have controller=a, action=b and id=c.

This situation can be avoided if you specify more strict requirements to URLs - for example, you may want IDs to be numerical only. Restrictions are specified in fourth parameter of routes.MapRoute() function.

Another approach for disambiguation is specifying separate routes for all of your controllers (usually you won't have much of them in your app) before generic route for sponsors.

UPD:

Most straightforward yet least maintainable way to distinguish between sponsor and non-sponsor routes is specifying controller-specific routes, like this:

public static void RegisterRoutes(RouteCollection routes)
{
...
     routes.MapRoute(
     "HomeRoute",
     "Home/{action}/{id}", // URL with parameters
     new { controller = "Home", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
     );
     routes.MapRoute(
     "AccountRoute",
     "Account/{action}/{id}", // URL with parameters
     new { controller = "Account", action = "Index", id = UrlParameter.Optional, sponsor=string.Empty }
     );

     ...

     routes.MapRoute(
     "SponsorRoute",
     "{sponsor}/{controller}/{action}/{id}", // URL with parameters
     new { controller = "Home", action = "Index", id = UrlParameter.Optional }
     );

...
}

Note that here all controller-specific routes must be added before SponsorRoute.

More complex yet more clean way is implementing RouteConstraints for sponsor and controller names as described in answer from @counsellorben.

like image 154
Sergey Kudriavtsev Avatar answered Oct 13 '22 02:10

Sergey Kudriavtsev