要解决您的问题,您必须考虑以下几点:
- 您可以注册多个路线。第一个可以处理 URL 的注册路由将处理它。
- 您可以使用除斜线
/ 之外的其他内容作为分隔符,以区分路线的某些部分
- 您可以使用参数约束(通常是正则表达式)来更轻松地发现参数是否属于一种或其他类型
- 你可以为你的参数指定默认值,如果你这样做了,动作方法必须有默认值(除非 MVC,它只要求它们可以为空或引用类型)
由于您没有说明您的 URL 的外观,我将向您展示我自己的示例。
假设您有一个 TestController Web API Controller 类,其操作如下:
// GET api/Test/TestAction/ ...
[HttpGet]
public object TestAction(int param1, DateTime startDate, DateTime endDate,
int? param2 = null)
{
return new
{
param1 = param1,
param2 = param2,
startDate = startDate,
endDate = endDate
}.ToString();
}
注意:对于默认路由,名为 GetXxx 的 Web API 控制器方法可用于 HTTP GET,名为 PostXxx 的方法可用于 HTTP POST 等等。但是,在 URL 模板中包含 Controller 和 Action 后,您必须使用 [HttpXxx] 属性使您的方法可用于所需的 HTTP 方法。
中间的可选参数
在第一个示例中,我假设param1 和param2 都是整数,而stardDate 和endDate 是日期:
http://myhost/api/Mycontroller/Myaction/12/22/2014-12-01/2014-12-31
http://myhost/api/Mycontroller/Myaction/22/2014-12-01/2014-12-31
如果您希望第一个 URL 匹配如下参数:
param1 = 12; param2 = 22; startDate = 2014-12-01; endData = 2014-12-31
第二个像这样:
param1 = 12; param2 = null; startDate = 2014-12-01; endData = 2014-12-31
您需要注册两条路由,一条将匹配每个可能的 URL 结构,即
// for the 1st
routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}"
// for the 2nd
routeTemplate: "api/{controller}/{action}/{param1}/{startDate}/{endDate}"
请注意,在这种情况下,两个路由是互斥的,即单个 URL 只能匹配其中一个路由,因此您可以在任何其他路由中注册它们。
但是,您必须注意第二个 URL 没有为 param2 定义值,而 TestAction 方法需要它。这是行不通的:您必须在控制器的方法和路由注册中包含此参数的默认值:
- 动作参数
int? param2 = null(C#要求可选参数是最后一个)。
- 路由必须包含默认值:
defaults: new { param2 = RouteParameter.Optional }
这是解决中间问题中可选参数的方法。通常,您需要根据可选参数的数量定义多个路由,并在 Web API 操作方法中使用默认值声明这些参数。
注意:正如我在上面写的,在 MVC 中,您不需要在方法参数中指定默认值即可使其工作
参数约束
为路由参数指定约束有两个后果:
- 保证参数值具有预期的格式
- 最重要的是,路由只会在格式符合预期的情况下处理 URL。因此,这有助于您使您的网址更具选择性,从而使其更加灵活。
你只需要在路由注册上添加一个constraint参数,像这样:
config.Routes.MapHttpRoute(
name: "Multiparam2",
routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}",
constraints: new
{
startDate = @"20\d\d-[0-1]?\d-[0-3]?\d", // regex
endDate = @"20\d\d-[0-1]?\d-[0-3]?\d" // regex
},
defaults: new object { }
);
请注意,必须指定 defaults 参数,即使它为空。
注意:这种情况下的约束是一个正则表达式,它只匹配年份 20XX 中的日期,月份表示为单个数字,或 0x 或 1x,日期为单个数字或 0x、1x , 2x 或 3x,用破折号分隔。所以这个正则表达式将匹配2012-1-1 或2015-12-30,但不匹配1920-12-30。您应该根据您的需要调整正则表达式。
最后的可选参数
此时我已经解释了如何支持可选参数,以及如何为它们指定格式(约束)以匹配路由模板。
定义可选参数的常用方法是在 URL 模板的末尾进行,在这种情况下,如果路由中缺少参数,则它们必须全部位于路由的末尾。 (将其与中间的 optional 进行比较:它们需要不同的路线)。
在本例中,如果要使param2、startDate和endDate可选,则必须在路由注册中定义它们,并在action方法中设置默认参数值。
最终代码如下所示:
[HttpGet]
public object TestAction(int param1, int? param2 = null, DateTime? startDate = null,
DateTime? endDate = null)
{
return new
{
param1 = param1,
param2 = param2,
startDate = startDate,
endDate = endDate
}.ToString();
}
config.Routes.MapHttpRoute(
name: "Multiparam1",
routeTemplate: "api/{controller}/{action}/{param1}/{startDate}/{endDate}",
constraints: new
{
startDate = @"20\d\d-[0-1]?\d-[0-3]?\d",
endDate = @"20\d\d-[0-1]?\d-[0-3]?\d"
},
defaults: new
{
param2 = RouteParameter.Optional,
startDate = RouteParameter.Optional,
endDate = RouteParameter.Optional
}
);
config.Routes.MapHttpRoute(
name: "Multiparam2",
routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}",
constraints: new
{
startDate = @"(20\d\d-[0-1]?\d-[0-3]?\d)?",
endDate = @"(20\d\d-[0-1]?\d-[0-3]?\d)?"
},
defaults: new
{
startDate = RouteParameter.Optional,
endDate = RouteParameter.Optional
}
);
注意,在这种情况下:
- 路由可能不匹配,因此它们必须按正确的顺序注册,如图所示。如果您首先注册了
Multiparam2 路由,它将错误地处理这样的URL:http://localhost:1179/api/test/testaction/1/2014-12-12/2015-1-1,param1=1; param2="2014-12-12"; startDate="2015-1-1"。 (您可以通过对仅接受数字的 param2 附加限制来避免这种情况,例如 param2=@"\d+")
- 操作必须具有
startDate 和endDate 的默认值。
结论
您可以谨慎处理不同位置的默认参数:
- 以正确的顺序注册路由
- 在路由中定义默认参数,在控制器动作中定义默认值
- 使用约束
如果您仔细计划路线的外观,您可以通过一些路线和可选参数获得所需的内容。