消除RESTful服务的歧义

时间:2014-04-13 13:23:51

标签: c# asp.net-mvc-3 rest asp.net-mvc-routing restful-url

我在之前的项目中广泛使用过WCF。最近,我一直在探索使用ASP.NET Web API创建RESTful服务。在研究了REST服务的DO和DOT,甚至尝试了它之后,我有一个相当直截了当的问题。

假设我有一个UsersController(继承ApiController),我需要有3个GET类型的操作方法:


    GetUsers()
    GetUserById(string id)
    GetUserByName(string name)

假设我在 WebApiConfig

中也有以下路线

    config.Routes.MapHttpRoute(
        name: "Users",
        routeTemplate: "api/users/{id}",
        defaults: new { controller = "users", id = RouteParameter.Optional }
    );

http://localhost:<port>/api/users显然会调用GetUsers()

当我需要调用带有单个参数的两个操作方法中的任何一个时,问题就出现了。

我想

http://localhost:<port>/api/users/5c6fe209-821e-475f-920d-1af0f3f52a82调用GetUserById(string id)

http://localhost:<port>/api/users/jdoe调用GetUserByName(string name)

我期望会发生的是,我会得到一个错误,或者只会调用第一个动作方法。

由于在消除歧义的路径上引入操作被视为偏离纯RESTful服务,如何使不同的URL调用相应的操作方法?我已经浏览了网页,大多数RESTful服务示例(由纯粹主义者)停在第一个操作方法来检索所有内容,而第二个操作方法则检索单个项目。

1 个答案:

答案 0 :(得分:1)

这可以使用更具体的约束路线来实现。以下示例与您尝试实现的类似:

config.Routes.MapHttpRoute(
    name: "ById",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { action = "GetById" },
    constraints: new { id = @"\d+" }
);

config.Routes.MapHttpRoute(
    name: "ByName",
    routeTemplate: "api/{controller}/{name}",
    defaults: new { action = "GetByName", },
    constraints: new { name = @"\w+" }
);

config.Routes.MapHttpRoute(
    name: "All",
    routeTemplate: "api/{controller}",
    defaults: new { action = "GetAll", }
);

传递给MapHttpRoute的约束对象为不同的URL参数指定了正则表达式形式的约束。在此示例中,对于ById路由,我们仅在id参数为数字时才匹配。如果name参数是一个字母字符串,我们只匹配ByName。我们匹配所有没有参数。注意&#34; +&#34;在每个正则表达式上指定没有空值。路由按照定义的顺序进行匹配,因此您应该将最不具体的规则放在更具体的规则之下。

在您的情况下,您需要查找或编写与您正在使用的GUID格式匹配的正则表达式,并约束ById路由以匹配此表达式。然后,您需要在接受任何字符串的下方定义ByName路由。因为它在下面,只有在输入字符串不是GUID时才会被调用。

我还应该补充一点,如果您之前没有使用过MVC路由,那么它们就非常具体。您会注意到我的参数名称为ById的{id}和ByName的{name}。重要的是,这些参数与控制器方法上输入参数的确切名称相匹配,因为路由器使用此参数构建方法调用。即使您在操作上只有一个参数,如果名称未正确映射,您也会收到错误。