ASP.net MVC路由与可选的第一个参数

San*_*G B 10 optional-parameters asp.net-mvc-routing asp.net-mvc-3

我需要为其中一个网站提供以下功能.

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

根据[赞助商],必须自定义网页.

我尝试使用Application_Start和Session_Start注册路由,但无法使其正常工作.

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
     );
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,没有[赞助商]的默认行为也应该起作用.有人请告诉我,如果在MVC3 URL中有可选的第一个参数在技术上是可行的.如果是,请分享实施.谢谢.


更新的代码 按照Sergey Kudriavtsev的建议进行更改后,代码在给出值时起作用.如果未提供name,则MVC不会路由到控制器/操作.

请注意,这仅适用于家庭控制器(包括和非赞助商).对于其他控制器/操作,即使指定了sponsor参数,它也不是路由选择.

请建议需要修改的内容.

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 }
        );
    }
Run Code Online (Sandbox Code Playgroud)

行动方法

public ActionResult Index(string sponsor)
    {
    }
Run Code Online (Sandbox Code Playgroud)

Ser*_*sev 15

在您的情况下,sponsor不应将其视为URL的常量部分,而应视为可变部分.

在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 }
     );

...
}
Run Code Online (Sandbox Code Playgroud)

在您的控制器中,例如,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.
        }
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此参数的类型始终为,System.String并且路径模板组件{sponsor}的名称必须与string sponsor控制器中的action参数名称完全匹配.

UPD:为非赞助商案例增加了第二条路线.

请注意,此类设置会使您的逻辑变得复杂,因为您可能会混淆不同的网址,例如网址

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

可以匹配两个路线:第一个将赞助商= a,控制器= b和行动= c; 第二个将具有controller = a,action = b和id = c.

如果您对URL指定更严格的要求,则可以避免这种情况 - 例如,您可能希望ID仅为数字.限制在routes.MapRoute()函数的第四个参数中指定.

消除歧义的另一种方法是在为赞助商提供通用路线之前为所有控制器指定单独的路线(通常在您的应用中通常不会有太多路径).

UPD:

区分赞助商和非赞助商路线的最简单但最不易维护的方法是指定控制器特定的路线,如下所示:

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 }
     );

...
}
Run Code Online (Sandbox Code Playgroud)

请注意,此处必须 SponsorRoute 之前添加所有特定于控制器的路由.

更复杂但更干净的方法是实现赞助商和控制器名称的RouteConstraints,如@counsellorben的回答所述.


Ole*_*rov 9

就我而言,我使用以下两个路由器解决了这个问题:

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" }
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

CultureConstraint类看起来象下面这样:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

MultiCultureMvcRouteHandler像这样:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)