是否有新的ASP.net MVC 4的WebAPI更好的方式来处理嵌套的资源不是建立一种特殊的路由为每一个? (类似于此: ?嵌套资源ASP.Net MVC的支持 -这是在2009年发布)。
例如,我想处理:
/customers/1/products/10/
我见过一些例子ApiController
行动命名为比其他Get()
Post()
等,例如在这里我看到一个名为动作的一个例子GetOrder()
我找不到这虽然任何文件。 这是一种方式来实现这一目标?
是否有新的ASP.net MVC 4的WebAPI更好的方式来处理嵌套的资源不是建立一种特殊的路由为每一个? (类似于此: ?嵌套资源ASP.Net MVC的支持 -这是在2009年发布)。
例如,我想处理:
/customers/1/products/10/
我见过一些例子ApiController
行动命名为比其他Get()
Post()
等,例如在这里我看到一个名为动作的一个例子GetOrder()
我找不到这虽然任何文件。 这是一种方式来实现这一目标?
对不起,我有这样的一个多次为我自己找到解决办法更新。
似乎有很多的方法来解决这一个,但最有效的,到目前为止我所发现的是:
默认路由在添加此:
routes.MapHttpRoute(
name: "OneLevelNested",
routeTemplate: "api/{controller}/{customerId}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
那么这条路线将匹配在URL中任何控制器动作和匹配段名称。 例如:
/ API /客户/ 1 /订单将匹配:
public IEnumerable<Order> Orders(int customerId)
/ API /客户/ 1 /命令/ 123将匹配:
public Order Orders(int customerId, int id)
/ API /客户/ 1 /产品将匹配:
public IEnumerable<Product> Products(int customerId)
/ API /客户/ 1 /产品/ 123将匹配:
public Product Products(int customerId, int id)
该方法名称必须与路由指定的{}行动段相匹配。
从评论
由于RC你需要告诉每个动作哪种是可以接受的动词,即[HttpGet]
等。
编辑:尽管这个答案仍然适用的Web API 1,对Web API 2我强烈建议您使用丹尼尔Halan的答案 ,因为它是艺术的映射子资源的状态(等细节)。
有些人不喜欢,因为他们认为,这样做,他们将打破REST“意识形态”使用{}行动中的Web API ...我争辩说。 {}行动仅仅是一个结构,它有助于路由。 这是内部的实施和无关用于访问某个资源的HTTP动词。
如果你把行动HTTP动词的约束,并将其命名据此你没有违反任何RESTful的指引,并会落得更简单,更简洁的控制器,而不是万吨每个子资源单个控制器中。 记住:行动仅仅是一个路由机制,并将其内置于您的实现。 如果您对框架的斗争,那么有什么不妥,要么与框架或您的实现。 只是地图与列举HTTPMethod约束的路线,你是好去:
routes.MapHttpRoute(
name: "OneLevelNested",
routeTemplate: "api/customers/{customerId}/orders/{orderId}",
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "GET" }) },
defaults: new { controller = "Customers", action = "GetOrders", orderId = RouteParameter.Optional, }
);
你可以在这样的CustomersController处理这些:
public class CustomersController
{
// ...
public IEnumerable<Order> GetOrders(long customerId)
{
// returns all orders for customerId!
}
public Order GetOrders(long customerId, long orderId)
{
// return the single order identified by orderId for the customerId supplied
}
// ...
}
您也可以路线上创建相同的“资源”(订单)的行动:
routes.MapHttpRoute(
name: "OneLevelNested",
routeTemplate: "api/customers/{customerId}/orders",
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "POST" }) },
defaults: new { controller = "Customers", action = "CreateOrder", }
);
而在客户控制器相应处理:
public class CustomersController
{
// ...
public Order CreateOrder(long customerId)
{
// create and return the order just created (with the new order id)
}
// ...
}
是的,你还必须创造了很多的路线,只是因为网络API还是可以取决于路径不同方法而不是路线...但我认为这是吸尘器声明方式定义的路线,而不是拿出一个自定义的调度机制基于枚举或其他的技巧。
为了您的API的消费者它看起来完美的RESTful:
GET http://your.api/customers/1/orders
(映射到GetOrders(长)返回所有订单客户1)
GET http://your.api/customers/1/orders/22
(映射到GetOrders(很久很久)返回订单22客户1
POST http://your.api/customers/1/orders
(映射到CreateOrder(长),这将创建一个订单并将其返回给调用者(与刚创建的新ID)
但是,不要把我的字是一个绝对的真理。 我还用它进行试验,我认为MS未能妥善解决子资源的访问。
我强烈建议你尝试http://www.servicestack.net/一个不那么痛苦的经历写的REST API ......但不要误会我的意思,我喜欢的Web API,并用它的大部分我的专业项目,主要因为它是比较容易找到的程序员,已经“知道”它......对于我的个人项目,我更喜欢ServiceStack。
由于网络API 2,您可以使用路由属性来定义每个方法自定义路由,允许分层路由
public class CustomersController : ApiController
{
[Route("api/customers/{id:guid}/products")]
public IEnumerable<Product> GetCustomerProducts(Guid id) {
return new Product[0];
}
}
您还需要初始化WebApiConfig.Register属性映射()
config.MapHttpAttributeRoutes();
我不喜欢使用在ASP.NET Web API的路线“行动”的概念。 在REST的行动被认为是对HTTP动词。 我只需使用父控制器的概念来实现我的一个有点普通,有点优雅的方式解决。
https://stackoverflow.com/a/15341810/326110
下面是这个问题的答案完全复制,因为我不知道该怎么做,当一个后回答了两个做题:(
我想在一个更一般的方式来处理这个问题,而不是直接与接线了ChildController controller = "Child"
,因为作者Abhijit噶当派一样。 我有几个孩子控制器和不想们必须为每一个特定的路线,与controller = "ChildX"
和controller = "ChildY"
一遍又一遍。
我WebApiConfig
看起来是这样的:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ChildApi",
routeTemplate: "api/{parentController}/{parentId}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
我的父母控制器非常标准,并符合上述缺省路由。 样本孩子控制器是这样的:
public class CommentController : ApiController
{
// GET api/product/5/comment
public string Get(ParentController parentController, string parentId)
{
return "This is the comment controller with parent of "
+ parentId + ", which is a " + parentController.ToString();
}
// GET api/product/5/comment/122
public string Get(ParentController parentController, string parentId,
string id)
{
return "You are looking for comment " + id + " under parent "
+ parentId + ", which is a "
+ parentController.ToString();
}
}
public enum ParentController
{
Product
}
enum
,所以我仍然有在两个不同的地方来管理父控制器。 它可以有很容易得到一个字符串参数,但我想,以防止api/crazy-non-existent-parent/5/comment/122
的工作。 有可能是一个更好的解决方案,甚至更普遍的,但正如我所说,这对我的作品。