我正在尝试在MVC中设置自定义路由,以便采用以下格式从另一个系统获取URL:
../ABC/ABC01?Key=123&Group=456
第二个ABC之后的01是一个步骤编号,这将改变,键和组参数将改变。我需要将此路由路由到控制器中的一个操作,步骤编号键和组作为参数。我尝试了以下代码,但它抛出异常:
代码:
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.`
答案 0 :(得分:39)
您不能在路线中包含查询字符串。试试这样的路线:
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会自动将查询字符串参数映射到控制器中方法中的参数。
答案 1 :(得分:4)
在定义路线时,您不能在路线的开头使用/
:
routes.MapRoute("OpenCase",
"/ABC/{controller}/{key}/{group}", <-- Bad; see / at beginning
new { controller = "", action = "OpenCase" },
new { key = @"\d+", group = @"\d+" }
);
routes.MapRoute("OpenCase",
"ABC/{controller}/{key}/{group}", <-- Good; No / at 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}
替换网址的那一部分的原因。
由于您还有一条定义“密钥”和“组”的路由,上述路由也会捕获您的初始网址并将其发送给操作。
答案 2 :(得分:1)
没有理由在新的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 ());
}
答案 3 :(得分:0)
查询字符串参数通常特定于该控制器和该特定应用程序逻辑。
因此,如果没有在路线规则中写出这一点,那就更好了。
您可以通过以下方式在动作参数上嵌入查询字符串的检测。
我认为最好有一个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"}
);
我已经使用此方法在控制器操作上获取多个字段键值。