简体   繁体   English

多个可选参数路由

[英]Multiple optional parameters routing

I have the following route definition in my webapi project. 我的webapi项目中有以下路由定义。 I have problem one of the parameter is not passed. 我有问题,其中一个参数未通过。 eg; 例如;

when i call /Controller/Action/param2/startdate/enddate the value i passed for param2 is taken for param1 and vice versa.The problem is, the RoutingModule can not detect that the provided route value is for param2 not param1 当我调用/ Controller / Action / param2 / startdate / enddate时,我为param2传递的值是param1,反之亦然。问题是,RoutingModule无法检测到提供的路由值是param2而不是param1

It works if i use querystring in the url but doesn't want to use querystring. 如果我在url中使用查询字符串但不想使用查询字符串,它可以工作。 Appreciate your help. 感谢您的帮助。

Is there any way to achieve what i expect? 有没有办法达到我的期望?

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

Thanks 谢谢

To solve your problem you must take into account this things: 要解决您的问题,您必须考虑以下事项:

  • you can register more than one route. 您可以注册多条路线。 The first registered route that can handle an URL, will handle it. 可以处理URL的第一个注册路由将处理它。
  • you can use something apart from slash / as separator, to make parts of a route distinguishable 你可以使用斜杠/作为分隔符之外的东西,使路线的某些部分可以区分
  • you can use parameter constraints, usually regular expressions, to make it easier to discover if a parameter is of one or other kind 您可以使用参数约束(通常是正则表达式)来更容易地发现参数是一种还是其他种类
  • you can specify default values for your parameters, and, if you do so, the action method must have default values for them (unless MVC, that only requires them to be nullable or of reference type) 您可以为参数指定默认值,如果这样做,操作方法必须具有默认值(除非MVC,只要求它们可以为空或引用类型)

As you didn't tell how your URL looks like I'll show you my own examples. 由于您没有告诉您的网址如何,我会向您展示我自己的示例。

Let's suppose that you have a TestController Web API Controller class with an action like this: 假设您有一个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();
}

NOTE: with the default routes a Web API controller's method named GetXxx is available to HTTP GET, a method named PostXxx is available to HTTP POST and so on. 注意:对于HTTP GET,可以使用默认路由Web API控制器的名为GetXxx的方法,HTTP POST可以使用名为PostXxx的方法,依此类推。 However, once you include Controller and Action in the URL template, you must use the [HttpXxx] attributes to make your method available to the required HTTP method. 但是,一旦在URL模板中包含ControllerAction ,就必须使用[HttpXxx]属性使您的方法可用于所需的HTTP方法。

Optional parameter(s) in the middle 中间的可选参数

In this first example, I suppose that both param1 , and param2 are integer numbers, and stardDate and endDate are dates: 在第一个例子中,我认为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

If you want the first URL to match parameters like these: 如果您希望第一个URL匹配以下参数:

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

and the second like these: 第二个像这样:

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

You need to register two routes, one that will match each possible URL structure, ie 您需要注册两个路由,一个匹配每个可能的URL结构,即

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

Note that, in this case, both routes are mutually exclusive, ie a single URL can match only one of the routes, so you can register them in any other. 请注意,在这种情况下,两个路由是互斥的,即单个URL只能匹配其中一个路由,因此您可以在任何其他路由中注册它们。

However, you must notice that the second URL doesn't define a value for param2 , and the TestAction method requires it. 但是,您必须注意第二个URL没有为param2定义值, TestAction方法需要它。 This wouldn't work: you must include a default value for this parameter, both in the controler's method and in the route registration: 这不起作用:您必须在控制器的方法和路径注册中包含此参数的默认值:

  • action parameter int? param2 = null 动作参数int? param2 = null int? param2 = null (C# requires optional parameter to be the last ones). int? param2 = null (C#要求可选参数为最后一个)。
  • the route must include the default: defaults: new { param2 = RouteParameter.Optional } 路由必须包含默认值: defaults: new { param2 = RouteParameter.Optional }

This is the way to solve the optional parameter in the middle problem. 这是解决中间问题中可选参数的方法。 In general, you'll need to define several routes, depending on how many optional parameters there are, and declare this parameters, with default values, in the Web API action method. 通常,您需要定义多个路由,具体取决于有多少可选参数,并在Web API操作方法中使用默认值声明此参数。

NOTE: as I wrote above, in MVC you don't need to specify a default value in the method parameter for this to work 注意:正如我上面所写,在MVC中,您无需在方法参数中指定默认值即可使用

Parameter constraints 参数约束

Specifying constrains for a route parameter has two consequences: 指定路由参数的约束有两个结果:

  1. There's a warranty that the parameter value has the expected format 保证参数值具有预期的格式
  2. Most importantly, the route will only handle the URL if the format is the expected one. 最重要的是,如果格式是预期的格式,路由将只处理URL。 So this helps you make your URL more selective, thus making it more flexible. 这样可以帮助您提高URL的选择性,从而使其更加灵活。

You simply need to add a constraint parameter on the route registration, like this: 您只需在路由注册上添加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 { }
);

Note that it's necessary to specify a defaults parameter, even if it's empty. 请注意,必须指定defaults参数,即使它是空的。

NOTE: the constraints in this case are a regex that only matches dates in the year 20XX, the month expressed as a single digit, or as 0x or 1x, and the date as a single digit or 0x, 1x, 2x or 3x, separated by dashes. 注意:在这种情况下的约束是一个正则表达式,只匹配20XX年份的日期,表示为单个数字的月份,或0x或1x,日期作为单个数字或0x,1x,2x或3x,分开破折号。 So this regex will match 2012-1-1 or 2015-12-30 , but not 1920-12-30 . 所以这个正则表达式将匹配2012-1-12015-12-30 ,但不是1920-12-30 You should adapt the regex to your needs. 你应该根据你的需要调整正则表达式。

Optional parameters at the end 最后的可选参数

By this time I've explained how to support optional parameters, and how to specify formats (constraints) for them, to match a route template. 到这时我已经解释了如何支持可选参数,以及如何为它们指定格式(约束),以匹配路由模板。

The usual way to define optional parameters is to do it at the end of the URL template, and, in this case, if there are missing params in a route, they must be all at the end of the route. 定义可选参数的常用方法是在URL模板的末尾执行此操作,在这种情况下,如果路径中缺少参数,则它们必须全部位于路径的末尾。 (Compare this with optional in the middle: they require different routes). (将其与中间的可选项进行比较:它们需要不同的路线)。

In this example, if you want to make optional the param2 , and the startDate and endDate , you must define them in the route registration, and set default parameter values in the action method. 在此示例中,如果要使param2startDateendDate可选,则必须在路径注册中定义它们,并在action方法中设置默认参数值。

The final code would look like this: 最终的代码如下所示:

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

Note, that, in this case: 请注意,在这种情况下:

  1. the routes could be mismatched, so they must be registered in the right order, as shown. 路线可能不匹配,因此必须按正确的顺序进行登记,如图所示。 If you registered first the Multiparam2 route, it would erroneously handle an URL like this: http://localhost:1179/api/test/testaction/1/2014-12-12/2015-1-1 , with param1=1; param2="2014-12-12"; startDate="2015-1-1" 如果您首先注册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" param1=1; param2="2014-12-12"; startDate="2015-1-1" param1=1; param2="2014-12-12"; startDate="2015-1-1" . param1=1; param2="2014-12-12"; startDate="2015-1-1" (You could avoid this with an additional constraint on param2 that only accepts numbers, like param2=@"\\d+" ) (您可以通过对param2的附加约束来避免这种情况,该约束仅接受数字,例如param2=@"\\d+"
  2. the action must have default values for startDate and endDate . 该操作必须具有startDateendDate默认值。

Conclusions 结论

You can handle default parameters in different positions by carefully: 您可以仔细处理不同位置的默认参数:

  • registering routes in the right order 以正确的顺序注册路线
  • define default parameters in the route, and also default values in the controller's action 定义路径中的默认参数,以及控制器操作中的默认值
  • use constraints 使用约束

If you plan carefully how your routes look like, you can get what you need with a few routes and optional parameters. 如果您仔细计划路线的样子,您可以通过几条路线和可选参数获得所需的路线。

JotaBe answer was nice and complete. JotaBe答案很好而且完整。 Just you have to consider if parameters are optional you have to write routeTemplate with the order from lowest parameters to highest. 只需要考虑参数是否可选,您必须使用从最低参数到最高参数的顺序编写routeTemplate。

Just like : 就像 :

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM