C# 多个可选参数路由

C# 多个可选参数路由,c#,asp.net-mvc-4,asp.net-web-api,url-routing,asp.net-web-api-routing,C#,Asp.net Mvc 4,Asp.net Web Api,Url Routing,Asp.net Web Api Routing,我的webapi项目中有以下路由定义。我有一个问题,其中一个参数没有传递。eg 当我调用/Controller/Action/param2/startdate/enddate时,我为param2传递的值将用于param1,反之亦然。问题是,RoutingModule无法检测到提供的路由值是否用于param2而不是param1 如果我在url中使用querystring,但不想使用querystring,那么它可以工作。谢谢你的帮助 有没有办法达到我的期望 config.Routes.MapHtt

我的webapi项目中有以下路由定义。我有一个问题,其中一个参数没有传递。eg

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

如果我在url中使用querystring,但不想使用querystring,那么它可以工作。谢谢你的帮助

有没有办法达到我的期望

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

谢谢

要解决您的问题,您必须考虑以下几点:

  • 您可以注册多条路线。可以处理URL的第一个注册路由将处理它
  • 您可以使用除斜杠
    /
    之外的东西作为分隔符,以使路由的各个部分可以区分
  • 您可以使用参数约束,通常是正则表达式,以便更容易地发现参数是一种还是另一种
  • 您可以为参数指定默认值,如果这样做,则操作方法必须具有这些参数的默认值(MVC除外,因为MVC只要求这些参数为null或引用类型)
因为你没有告诉我你的URL是什么样子的,我会给你看我自己的例子

假设您有一个
TestController
Web API控制器类,其操作如下:

// 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();
}
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 { }
);
[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
    }
);
注意:使用默认路由,HTTP GET可以使用名为
GetXxx
的Web API控制器方法,HTTP POST可以使用名为
PostXxx
的方法,依此类推。但是,在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
第二个是这样的:

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}

这是解决中间问题中可选参数的方法。通常,您需要根据可选参数的数量定义多个路由,并在WebAPI操作方法中使用默认值声明这些参数

注意:正如我在上面所写的,在MVC中,不需要在方法参数中指定默认值,就可以工作

参数约束 为管线参数指定约束有两个后果:

  • 保证参数值具有预期格式
  • 最重要的是,只有当URL的格式是预期的格式时,路由才会处理URL。因此,这有助于您提高URL的选择性,从而使其更灵活
  • 您只需在路线注册上添加一个
    约束
    参数,如下所示:

    // 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();
    }
    
    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 { }
    );
    
    [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
        }
    );
    
    请注意,即使参数为空,也必须指定
    默认值
    参数

    注意:本例中的约束条件是一个正则表达式,它只匹配20XX年的日期、表示为一位数字或0x或1x的月份以及表示为一位数字或0x、1x、2x或3x的日期(用破折号分隔)。因此,该正则表达式将匹配
    2012-1-1
    2015-12-30
    ,但不匹配
    1920-12-30
    。您应该根据自己的需要调整正则表达式

    末尾的可选参数 至此,我已经解释了如何支持可选参数,以及如何为它们指定格式(约束),以匹配管线模板

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

    在本例中,如果要使
    param2
    startDate
    endDate
    可选,则必须在路线注册中定义它们,并在操作方法中设置默认参数值

    最终的代码如下所示:

    // 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();
    }
    
    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 { }
    );
    
    [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
    ,参数为1;param2=“2014-12-12”;startDate=“2015-1-1”。(您可以通过对仅接受数字的param2附加约束来避免这种情况,如
    param2=@“\d+”
  • 操作必须具有
    startDate
    endDate
    的默认值
  • 结论 您可以通过以下方法小心地处理不同位置的默认参数:

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

    如果你仔细规划你的路线,你可以通过一些路线和可选参数得到你所需要的。

    JotaBe的回答很好,很完整。只是你没有