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

时间:2011-11-29 12:38:25

标签: asp.net-mvc-3 asp.net-mvc-routing optional-parameters

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

http://www.example.com/ [赞助] / {控制器} / {动作}

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

我尝试使用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
     );
    }
}

此外,没有 [赞助商] 的默认行为也应该起作用。 有人请告诉我,如果在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 }
        );
    }

行动方法

public ActionResult Index(string sponsor)
    {
    }

4 个答案:

答案 0 :(得分: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 }
     );

...
}

在您的控制器中,例如,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.
        }
        ...
    }
}

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

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

...
}

请注意,此处所有特定于控制器的路线必须先添加 SponsorRoute。

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

答案 1 :(得分: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" }
    );
  }
}

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

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

答案 2 :(得分:4)

除了在默认路由之前添加第二条路线之外,正如谢尔盖在他的回答中所说,你还必须在初始路由中添加RouteConstraint,以强制{sponsor}令牌是名称有效的赞助商。

您可以在此答案中使用RouteConstraint:Asp.Net Custom Routing and custom routing and add category before controller

请记住,您还必须执行一个规则,即赞助商名称不能与您的任何控制器名称相同。

答案 3 :(得分:0)

我将以简单的示例向您展示您不必更改 Route.config.cs 只需要在 Route.config.cs 中放入

可选URI参数优先和默认值

<强> Route.config.cs

routes.MapMvcAttributeRoutes();

<强>控制器

[Route("{Name}/Controller/ActionName")]
        public ActionResult Details(string Name)
        {            

              // some code here 

            return View();
        }

<强>结果

<强>本地主机:2345 /名称/ controllername / actionname / ID(可选)