ASP.net MVC routing with optional first parameter

前端 未结 4 1540
南笙
南笙 2020-12-08 23:32

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

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

Depending on the

相关标签:
4条回答
  • 2020-12-08 23:58

    In my case, I've resolved this issue using the following two routers:

    public class RouteConfig
    {
      public static void RegisterRoutes(RouteCollection routes)
      {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
        routes.MapRoute(
            name: "MultiCulture",
            url: "{culture}/{controller}/{action}",
            defaults: new { controller = "Home", action = "Index" },
            constraints: new { culture = new CultureConstraint(CultureFactory.All.Select(item => item.UrlPrefix).ToArray()) }
        ).RouteHandler = new MultiCultureMvcRouteHandler();
    
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}",
            defaults: new { controller = "Home", action = "Index" }
        );
      }
    }
    

    Where CultureConstraint class looks like below:

    public class CultureConstraint : IRouteConstraint
    {
      private readonly string[] values;
    
      public CultureConstraint(params string[] values)
      {
        this.values = values;
      }
    
      public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary routeValues, RouteDirection routeDirection)
      {
        string value = routeValues[parameterName].ToString();
    
        return this.values.Contains(value);
      }
    }
    

    And MultiCultureMvcRouteHandler like this:

    public class MultiCultureMvcRouteHandler : MvcRouteHandler
    {
      protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
      {
        var culture = CultureManager.GetCulture(requestContext.RouteData);
    
        if (culture != null)
        {
          var cultureInfo = new CultureInfo(culture.Name);
    
          Thread.CurrentThread.CurrentUICulture = cultureInfo;
          Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name);
        }
    
        return base.GetHttpHandler(requestContext);
      }
    }
    
    0 讨论(0)
  • 2020-12-09 00:07

    In addition to adding a second route before the default route, as Sergey said in his answer, you also must add a RouteConstraint to the initial route, to enforce that the {sponsor} token is the name of a valid sponsor.

    You can use the RouteConstraint in this answer: Asp.Net Custom Routing and custom routing and add category before controller

    Remember that you must also enforce a rule that a sponsor name cannot be the same as any of your controller names.

    0 讨论(0)
  • 2020-12-09 00:11

    i will show you in simple example you don't have to change in Route.config.cs only you have to do in Route.config.cs just put in

    Optional URI Parameters First and Default Values

    Route.config.cs

    routes.MapMvcAttributeRoutes();
    

    Controller

    [Route("{Name}/Controller/ActionName")]
            public ActionResult Details(string Name)
            {            
    
                  // some code here 
    
                return View();
            }
    

    Results

    localhost:2345/Name/controllername/actionname/id(optional)

    0 讨论(0)
  • 2020-12-09 00:14

    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.

    0 讨论(0)
提交回复
热议问题