消除RESTful服务的歧义
本文关键字:歧义 服务 RESTful 消除 | 更新日期: 2023-09-27 17:58:03
我在以前的项目中广泛使用了WCF。最近,我一直在探索在创建RESTful服务时使用ASP.NET Web API。在研究了RESTful服务的DO和DONT,甚至在实践中进行了尝试之后,我有一个相当简单的问题。
假设我有一个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服务的例子(由纯粹主义者)都停留在第一个操作方法来检索所有内容,第二个操作方法检索单个项目。
这可以使用更具体的受限路由来实现。下面的例子与您试图实现的目标类似:
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的constraints对象以正则表达式的形式为不同的URL参数指定约束。在本例中,对于ById路由,只有当id参数为数字时,我们才会匹配。只有当name参数是一个由alpha字符组成的字符串时,我们才匹配ByName。我们无参数匹配All。请注意,每个正则表达式上的"+"不指定空值。路由是按照定义的顺序匹配的,所以你应该把最不具体的规则放在更具体的规则下面。
在您的情况下,您需要找到或编写一个与您正在使用的GUID格式匹配的正则表达式,并约束ById路由以匹配此表达式。然后,您需要在下面定义接受任何字符串的ByName路由。因为它在下面,所以只有当输入字符串不是GUID时才会调用它。
我还应该补充一点,如果你以前没有使用过MVC路由,它们是非常具体的。您会注意到,我的参数名称为ById的{id}和ByName的{name}。这些参数与控制器方法上输入参数的确切名称匹配是很重要的,因为路由器构建方法调用就是使用这个名称的。即使一个操作只有一个参数,如果名称映射不正确,也会出现错误。