多个可选参数路由

时间:2014-12-29 16:38:47

标签: c# asp.net-mvc-4 asp.net-web-api url-routing asp.net-web-api-routing

我的webapi项目中有以下路由定义。我有问题,其中一个参数未通过。例如;

当我调用/ Controller / Action / param2 / startdate / enddate时,我为param2传递的值是param1,反之亦然。问题是,RoutingModule无法检测到提供的路由值是否为param2而不是param1 < / p>

如果我在url中使用查询字符串但不想使用查询字符串,它会起作用。感谢您的帮助。

有没有办法达到我的期望?

config.Routes.MapHttpRoute(
    name: "RetrieveHistory",
    routeTemplate: "{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}",
    defaults: new
    {
        controller = "Vend",
        action = "RetrieveUtrnHistory",
        param1 = RouteParameter.Optional,
        param2 = RouteParameter.Optional,
        starDate = RouteParameter.Optional,
        endDate = RouteParameter.Optional
    });

由于

2 个答案:

答案 0 :(得分:15)

要解决您的问题,您必须考虑以下事项:

  • 您可以注册多条路线。可以处理URL的第一个注册路由将处理它。
  • 你可以使用斜杠/之外的东西作为分隔符,使路线的某些部分可以区分
  • 您可以使用参数约束(通常是正则表达式)来更容易地发现参数是一种还是其他种类
  • 您可以为参数指定默认值,如果这样做,则action方法必须具有默认值(除非MVC,只要求它们可以为空或引用类型)

由于您没有告诉您网址的外观,我会向您展示我自己的示例。

假设您有一个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();
}

注意:对于HTTP GET,可以使用默认路由Web API控制器的名为GetXxx的方法,HTTP POST可以使用名为PostXxx的方法,依此类推。但是,在网址模板中加入ControllerAction后,您必须使用[HttpXxx]属性使您的方法可用于所需的HTTP方法。

中间的可选参数

在第一个示例中,我认为param1param2都是整数,stardDateendDate是日期:

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

如果您希望第一个网址匹配以下参数:

param1 = 12; param2 = 22; startDate = 2014-12-01; endData = 2014-12-31

和第二个像这样:

param1 = 12; param2 = null; startDate = 2014-12-01; endData = 2014-12-31

您需要注册两条路线,一条路线将匹配每个可能的网址结构,即

// for the 1st
routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}"
// for the 2nd
routeTemplate: "api/{controller}/{action}/{param1}/{startDate}/{endDate}"

请注意,在这种情况下,两个路由是互斥的,即单个URL只能匹配其中一个路由,因此您可以在任何其他路由中注册它们。

但是,您必须注意第二个网址没有定义param2的值,TestAction方法需要它。这不起作用:您必须在控制器的方法和路径注册中包含此参数的默认值:

  • 操作参数int? param2 = null(C#要求可选参数为最后一个参数)。
  • 路线必须包含默认值:defaults: new { param2 = RouteParameter.Optional }

这是解决中间问题中可选参数的方法。通常,您需要定义多个路由,具体取决于有多少可选参数,并在Web API操作方法中使用默认值声明此参数。

注意:正如我上面所写,在MVC中,您无需在方法参数中指定默认值即可使用

参数约束

指定路由参数的约束有两个结果:

  1. 保证参数值具有预期的格式
  2. 最重要的是,如果格式是预期的格式,路由将只处理URL。因此,这有助于您提高URL的选择性,从而使其更加灵活。
  3. 您只需在路线注册中添加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-12015-12-30,但不匹配1920-12-30。您应该根据需要调整正则表达式。

    最后的可选参数

    此时我已经解释了如何支持可选参数,以及如何为它们指定格式(约束),以匹配路由模板。

    定义可选参数的常用方法是在URL模板的末尾执行此操作,在这种情况下,如果路径中缺少参数,则它们必须全部位于路径的末尾。 (比较中间的可选项:它们需要不同的路线)。

    在此示例中,如果要使param2以及startDateendDate可选,则必须在路由注册中定义它们,并在其中设置默认参数值行动方法。

    最终代码如下所示:

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

    请注意,在这种情况下:

    1. 路线可能不匹配,因此必须按正确的顺序进行注册,如图所示。如果您首先注册Multiparam2路由,则会错误地处理这样的网址:http://localhost:1179/api/test/testaction/1/2014-12-12/2015-1-1param1=1; param2="2014-12-12"; startDate="2015-1-1"。 (您可以通过对仅接受数字的param2的附加约束来避免这种情况,例如param2=@"\d+"
    2. 该操作必须具有startDateendDate的默认值。
    3. 结论

      您可以小心处理不同位置的默认参数:

      • 以正确的顺序注册路线
      • 定义路径中的默认参数,以及控制器操作中的默认值
      • 使用约束

      如果您仔细计划路线的样子,您可以通过一些路线和可选参数获得所需的信息。

答案 1 :(得分:0)

JotaBe的回答很好而且很完整。只是要考虑参数是否可选,就必须编写routeTemplate并按从最低参数到最高参数的顺序进行。

就像:

// for the 1st
routeTemplate: "api/{controller}/{action}/{param1}/{startDate}/{endDate}"

// for the 2nd
routeTemplate: "api/{controller}/{action}/{param1}/{param2}/{startDate}/{endDate}"