【问题标题】:How do I route a URL with a querystring in ASP.NET MVC?如何在 ASP.NET MVC 中使用查询字符串路由 URL?
【发布时间】:2011-10-19 23:54:00
【问题描述】:

我正在尝试在 MVC 中设置自定义路由,以从另一个系统获取以下格式的 URL:

../ABC/ABC01?Key=123&Group=456

第二个 ABC 之后的 01 是一个步数,它会改变,Key 和 Group 参数也会改变。我需要将此路由到控制器中的一个操作,其中步骤号键和组作为参数。我尝试了以下代码,但它引发了异常:

代码:

routes.MapRoute(
    "OpenCase", 
    "ABC/ABC{stepNo}?Key={key}&Group={group}",
    new {controller = "ABC1", action = "OpenCase"}
);

例外:

`The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character.`

【问题讨论】:

    标签: asp.net-mvc routing asp.net-mvc-routing


    【解决方案1】:

    定义路由时,不能在路由开头使用/:

    routes.MapRoute("OpenCase",
        "/ABC/{controller}/{key}/{group}", // Bad. Uses a / at the beginning
        new { controller = "", action = "OpenCase" },
        new { key = @"\d+", group = @"\d+" }
        );
    
    routes.MapRoute("OpenCase",
        "ABC/{controller}/{key}/{group}",  // Good. No / at the beginning
        new { controller = "", action = "OpenCase" },
        new { key = @"\d+", group = @"\d+" }
        );
    

    试试这个:

    routes.MapRoute("OpenCase",
        "ABC/{controller}/{key}/{group}",
        new { controller = "", action = "OpenCase" },
        new { key = @"\d+", group = @"\d+" }
        );
    

    那么你的操作应该如下所示:

    public ActionResult OpenCase(int key, int group)
    {
        //do stuff here
    }
    

    看起来您将stepNo 和“ABC”放在一起以获得ABC1 的控制器。这就是为什么我用{controller} 替换了URL 的那部分。

    由于您还有一个定义“键”和“组”的路由,因此上述路由还将捕获您的初始 URL 并将其发送到操作。

    【讨论】:

      【解决方案2】:

      查询字符串参数通常特定于该控制器和该特定应用程序逻辑。

      所以如果这不是写在路由规则中会更好,那是通用的。

      您可以通过以下方式在操作参数上嵌入查询字符串检测。

      我认为最好有一个Controller来处理StepNo。

      public class ABC : Controller
      {
          public ActionResult OpenCase(OpenCaseArguments arg)
          {
              // do stuff here
              // use arg.StepNo, arg.Key and arg.Group as You need
              return View();
          }        
      }
      
      public class OpenCaseArguments
      {
          private string _id;
          public string id
          {
              get
              {
                  return _id;
              }
      
              set
              {
                  _id = value; // keep original value;
                  ParseQueryString(value);
              }
          }
      
          public string  StepNo { get; set; }
          public string Key { get; set; }
          public string Group { get; set; }
      
          private void ParseQueryString(string qs)
          {
              var n = qs.IndexOf('?');
              if (n < 0) return;
              StepNo = qs.Substring(0, n); // extract the first part eg. {stepNo}
              NameValueCollection parms = HttpUtility.ParseQueryString(qs.Substring(n + 1));
              if (parms.Get("Key") != null) Key = parms.Get("Key");
              if (parms.Get("Group") != null) Group = parms.Get("Group");
          }
      
      }
      

      ModelBinder 将 {id} 值分配给 OpenCaseArguments 的 id 字段。 set 方法处理查询字符串拆分逻辑。

      并继续以这种方式路由。注意路由在 id 参数中获取您的查询字符串。

      routes.MapRoute(
          "OpenCase", 
          "ABC/OpenCase/{id}",
          new {controller = "ABC", action = "OpenCase"}
      );
      

      我已经使用这种方法来获取控制器操作的多个字段键值。

      【讨论】:

      • 请注意,MVC 会自动解析带有QueryStringValueProvider 的查询字符串。在操作方法中获取这些值所需要做的就是将与查询字符串键同名的参数添加到操作方法或模型中。无需为此构建自己的查询字符串解析器。
      【解决方案3】:

      没有理由在新的 ASP.NET MVC 项目中使用基于查询字符串的路由。对于从经典 ASP.NET 项目转换而来的旧项目,并且您希望保留 URL,它可能很有用。

      一种解决方案可以是属性路由。

      另一种解决方案是通过从 RouteBase 派生来编写自定义路由:

      public class MyOldClassicAspRouting : RouteBase
      {
      
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
          if (httpContext.Request.Headers == null) //for unittest
            return null;
      
          var queryString = httpContext.Request.QueryString;
      
          //add your logic here based on querystring
          RouteData routeData = new RouteData(this, new MvcRouteHandler());
          routeData.Values.Add("controller", "...");
          routeData.Values.Add("action", "...");
        }
      
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
           //Implement your formating Url formating here
           return null;
        }
      }
      

      并注册您的自定义路由类

      public static void RegisterRoutes(RouteCollection routes)
      {
        ...
      
        routes.Add(new MyOldClassicAspRouting ());
      }
      

      【讨论】:

        【解决方案4】:

        您不能在路由中包含查询字符串。尝试这样的路线:

        routes.MapRoute("OpenCase", "ABC/ABC{stepNo}",
           new { controller = "ABC1", action = "OpenCase" });
        

        然后,在你的控制器上添加这样的方法:

        public class ABC1 : Controller
        {
            public ActionResult OpenCase(string stepno, string key, string group)
            {
                // do stuff here
                return View();
            }        
        }
        

        ASP.NET MVC 会自动将查询字符串参数映射到控制器中方法中的参数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-28
          相关资源
          最近更新 更多