在ASP.net MVC 4的WebAPI嵌套资源在ASP.net MVC 4的WebAPI嵌套资源

2019-05-13 10:45发布

是否有新的ASP.net MVC 4的WebAPI更好的方式来处理嵌套的资源不是建立一种特殊的路由为每一个? (类似于此: ?嵌套资源ASP.Net MVC的支持 -这是在2009年发布)。

例如,我想处理:

/customers/1/products/10/

我见过一些例子ApiController行动命名为比其他Get() Post()等,例如在这里我看到一个名为动作的一个例子GetOrder() 我找不到这虽然任何文件。 这是一种方式来实现这一目标?

Answer 1:

对不起,我有这样的一个多次为我自己找到解决办法更新。

似乎有很多的方法来解决这一个,但最有效的,到目前为止我所发现的是:

默认路由在添加此:

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]等。



Answer 2:

编辑:尽管这个答案仍然适用的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。



Answer 3:

由于网络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();


Answer 4:

我不喜欢使用在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的工作。
  • 有可能使用反射或东西要做到这一点就没有separetly管理它飞的方式,但是这对我的作品现在。
  • 它不支持孩子的孩子。

有可能是一个更好的解决方案,甚至更普遍的,但正如我所说,这对我的作品。



文章来源: Nested resources in ASP.net MVC 4 WebApi