【问题标题】:ASP.NET MVC Route with dash带有破折号的 ASP.NET MVC 路由
【发布时间】:2009-05-15 12:19:02
【问题描述】:

我有 ASP.NET MVC 路由问题。

我准备了下面的路由表来映射这样的 url

mywebsite/mycontroller/myaction/14-longandprettyseoname

到参数:

14 => id(整数)

longandprettyseoname -> seo_name(字符串)

    routes.MapRoute(
        "myname",
        "mycontroller/myaction/{id}-{seo_name}", 
        new { controller = "mycontroller", action = "myaction", id = 0, seo_name = (string)null });

    routes.MapRoute(
        "Default",  
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = "" });

它适用于上面的 URL,但它有以下类型的 url 的问题

mywebsite/mycontroller/myaction/14-long-and-pretty-seo-name

这样可以让它工作吗?


编辑:

"mycontroller/myaction/{seo_name}-{id}"

似乎在工作

【问题讨论】:

  • 更简单的解决方案是使用诸如 mywebsite/mycontroller/mycation/14/long-and-pretty-seo-name 之类的 url,就像堆栈溢出一样?

标签: asp.net-mvc


【解决方案1】:

最明显的方法是使用约束。

由于你的 id 是一个整数,你可以添加一个约束来寻找一个整数值:

new { id = @"\d+" }

这是整个路线:

routes.MapRoute("myname","mycontroller/myaction/{id}-{seo_name}", 
        new { controller = "mycontroller", action = "myaction" }, 
        new { id = @"\d+"});

【讨论】:

  • 你会认为这行得通。但它不起作用。至少,不适合我。
【解决方案2】:

我的解决方案是将路线定义为:

routes.MapRoute("myname","mycontroller/myaction/{id}",  
        new { controller = "mycontroller", action = "myaction"}); 

并在 HTTP 处理程序中使用 Regex 手动解析 id 和 seoname:

        var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));
        var match = System.Text.RegularExpressions.Regex.Match((string)routeData.Values["id"], @"^(?<id>\d+)-(?<seoname>[\S\s]*)$");
        if (!match.Success)
        {
            context.Response.StatusCode = 400;
            context.Response.StatusDescription = "Bad Request";
            return;
        }

        int id = Int32.Parse(match.Groups["id"].Value);
        string seoname = match.Groups["seoname"].Value;

【讨论】:

    【解决方案3】:

    我认为该路线无法区分,因为它无法确定要拆分的“-”以指定 {id}{seo-name}

    在您的 SEO 名称中使用 下划线 怎么样?或者您可以只使用 SEO 名称作为实际的 {id}。如果 SEO 名称是唯一的,这是一个非常可行的选项,您可以将其用作数据库中该条目的伪主键(假设它从数据库中提取某些内容)

    此外,利用 Phil Haack 的 route debugger 了解哪些有效,哪些无效。

    【讨论】:

    • 我不希望 seo_name 是全局唯一的,所以这是将 id 字段放在开头的原因。如果它无法区分破折号,那么我可以将规则更改为 mycontroller/myaction/{id}/{seo_name} 对我来说没关系,但我不知道它是否违反任何 seo 规则/最佳实践
    【解决方案4】:

    定义一个特定的路由,例如:

            routes.MapRoute(
                "TandC", // Route controllerName
                "CommonPath/{controller}/Terms-and-Conditions", // URL with parameters
                new { controller = "Home", action = "Terms_and_Conditions" } // Parameter defaults
            );
    

    但这条路线必须在您的默认路线之前注册。

    【讨论】:

      【解决方案5】:

      您可以做的是创建一个自定义控制器工厂。这样您就可以使用自定义代码来决定何时需要调用哪个控制器。

      public class CustomControllerFactory : IControllerFactory
          {
              #region IControllerFactory Members
      
              public IController CreateController(RequestContext requestContext, string controllerName)
              {
                  if (string.IsNullOrEmpty(controllerName))
                      throw new ArgumentNullException("controllerName");
      
                  //string language = requestContext.HttpContext.Request.Headers["Accept-Language"];
                  //can be used to translate controller name and get correct controller even when url is in foreign language
      
                  //format controller name
                  controllerName = String.Format("MyNamespace.Controllers.{0}Controller",controllerName.Replace("-","_"));
      
                  IController controller = Activator.CreateInstance(Type.GetType(controllerName)) as IController;
                  controller.ActionInvoker = new CustomInvoker(); //only when using custominvoker for actionname rewriting
                  return controller;
              }
      
              public void ReleaseController(IController controller)
              {
                  if (controller is IDisposable)
                      (controller as IDisposable).Dispose();
                  else
                      controller = null;
              }
      
              #endregion
          }
      

      要使用这个自定义控制器工厂,你应该在你的 global.asax 中添加它

      protected void Application_Start()
              {
                  RegisterRoutes(RouteTable.Routes);
                  ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
              }
      

      请注意,这仅适用于控制器,不适用于动作...要在动作执行之前对动作进行自定义重写,请使用以下代码:

      public class CustomInvoker : ControllerActionInvoker
      {
          #region IActionInvoker Members
      
          public override bool InvokeAction(ControllerContext controllerContext, string actionName)
          {
              return base.InvokeAction(controllerContext, actionName.Replace("-", "_"));
          }
      
          #endregion
      }
      

      我从this blog 获得了大部分代码,并根据我的需要对其进行了调整。就我而言,我希望用破折号分隔控制器名称中的单词,但您不能创建名称中带有破折号的操作。

      希望这会有所帮助!

      【讨论】:

      • 当您对我的回答投反对票时,最好解释一下原因,这样我就知道出了什么问题。
      猜你喜欢
      • 2014-06-26
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 2011-02-21
      相关资源
      最近更新 更多