【问题标题】:ServiceStack Clients and Ambiguous RoutesServiceStack 客户端和模糊路由
【发布时间】:2014-01-02 15:23:33
【问题描述】:

我有一个服务堆栈服务,我们将调用 Orders,它具有标准 GET 路由

  • /orders - 获取所有客户
  • /orders/{Ids} - 获取特定客户

这一切都很好,花花公子,但我想我会添加另一条路线

  • /orders/customers/{CustomerId} - 获取具有特定客户 ID 的订单

这在浏览器中点击路由时会发现,但是当我使用 ServiceStack 客户端时,我得到了不明确的路由异常,它列出了三个路由。

我不太确定解决这个问题的最佳方法是什么..我正在做的不是正确的 RESTish 方法吗?

我知道我可以简单地将路线手动输入JsonServiceClient 之类的

client.Get<List<Orders>>("/orders/customers/7")

这会起作用,但我更愿意以键入的方式进行......即

client.Get(new OrdersRequest { CustomerId = 7 });

这是我正在使用的 RequestDTO 示例

public class OrdersRequest : IReturn<List<Orders>>
{
   public int[] Ids {get; set;}
   public CustomerId {get; set;}

   public OrdersRequest(params int[] ids)
   {
        this.Ids = ids;
   }
}

我必须为此使用不同的 Dto 还是...?

任何帮助或指向任何可以解决此问题的示例或创建服务的更好方法的指针将不胜感激。

谢谢

【问题讨论】:

  • 问题:按原样(可能不是正确的路线),如果您删除带有参数数组的构造函数,它会起作用吗?
  • 另外,我不认为在 Uri 本身中有一个 id 列表是可以接受的。也许路线应该是 /orders(获取所有客户的订单),并且在 Url 参数中,orders/?ids=1&ids=2&ids=3 @Scott 在如何创建最佳路线方面是正确的。

标签: web-services rest routes servicestack


【解决方案1】:

我的建议是您没有正确使用 REST。有a good answer about how to best structure a ServiceStack REST service。刚开始的时候很常见,我也遇到过这样的问题。

了解您的用例:

在您的具体情况下,如果我们查看 /orders/customers/7 这会更好,您是否这样想:

/customers/7/订单

你这样做的原因:

  • 它解决了您的路线模糊问题
  • 上下文很清楚。我们可以看到我们正在与 客户 7 合作,而无需导航很长的 url
  • 我们可以看到“与客户 7”我们想要他们的订单

考虑这样的路由:

/orders                   Everybody's Orders
/orders/1                 Order 1 (without being aware of the customer it belongs to)
/customers                All Customers
/customers/7              Customer 7's details
/customers/7/orders       All Customer 7's orders
/customers/7/orders/3     Customer 7's order number 3

这样做的好处是对数据的操作是一致的。所以你想找到所有取消的订单:

/orders/cancelled

您想通过orderId取消特定订单

/orders/4/cancel

您想列出特定客户的未结订单

/customers/6/orders/open

您想列出客户 6 的已取消订单

/customers/6/orders/cancelled

您想取消正在查看的客户 6 的订单

/customers/6/orders/2/cancel

显然这些只是场景,您的路线会有所不同。

简化动作处理程序:

您可能希望定义您的操作处理程序,以便它们可以应对来自多个路线的情况。我的意思是,一个操作处理程序将负责列出订单

/orders
/customers/6/orders

我要做的是:

[Route("/orders","GET")]
[Route("/customers/{CustomerId}/orders","GET")]
public class ListOrdersRequest : IReturn<List<Order>>
{
    public int? CustomerId { get; set; }
}

所以你可以看到两个订单列表路由进来。如果他们使用/orders,那么我们的customerId 将没有值,但其他路由会有值。所以在我们的动作处理程序中,我们可以简单地测试一下:

public List<Order> Get(ListOrdersRequest request)
{
    // Use `CustomerId` to narrow down your search scope

    if(request.CustomerId.HasValue){
        // Find customer specific orders
    } else {
        // Find all orders
    }

    return orders;
}

客户端问题:

因此,为了解决您使用“类型化”客户端的问题。使用上述方法创建路由和操作处理程序将允许您执行以下操作:

client.Get(new ListOrdersRequest { CustomerId = 7 }); // To get customer 7's orders
client.Get(new ListOrdersRequest()); // All orders

因此为您提供了一种清晰的列出订单的方法。

最后的想法:

显然,这意味着您将不得不重做现有的工作,这可能会很痛苦,但这是最好的方法,值得付出努力。

我希望这可以帮助您了解最佳结构。


更新:

@stefan2410 要求我解决 Kyle 在 GET 请求的路由中使用 int[] 的问题:

如果您想在 GET 请求中使用 int[],您必须考虑在 URL 传输期间更改它,以便可以 RESTful 方式使用它。

所以你可以这样做:

class OrdersRequest
{
    public string Ids { get; set; }

    public OrdersRequest(int[] ids)
    {
        Ids = string.Join(",", Array.ConvertAll(ints, item => item.ToString()));
    }
}

client.Get(new OrdersRequest(new [] {1,2,3}));

创建路由/orders/1,2,3 并匹配/orders/{Ids}。这样做的问题是为了在服务器端使用 Id,您必须将字符串 "1,2,3" 转换回 int[]

处理请求中int[] 的更好方法是使用 POST。所以你可以这样做:

class OrdersRequest
{
    public int[] Ids { get; set; }

    public OrdersRequest(int[] ids)
    {
        Ids = ids;
    }
}    

client.Post(new OrdersRequest(new[] {1,2,3}));

创建路由/orders并匹配路由/orders

【讨论】:

  • 非常有帮助的答案,如果可以的话,我会给你+2。
  • @Scott,也许您对与用例匹配得更好的路线是对的,但我不明白歧义在哪里。 Dto 中存在错误(带有参数数组的构造函数。还有 /orders/{Ids} ,首先它表示 Orders 的 ID 而不是客户的 ID,其次,Get 中是否有可能在 Uri 中有一个整数数组?(当然是不正确的REST)
  • @stefan2410 是的,你是对的,在路由中传递一组 Id 是错误的。我认为凯尔可能简化了他的问题,消除了歧义,但他在访问发出请求(可能是其他路线)时确实通过AmbiguousRoutesException 说过。使用/orders/customers 让我相信他有结构性问题。你有什么困扰吗?
  • @Scott,您对最佳路线的回答非常好,但它隐藏了真正的问题。由于这个原因令人困惑。你能确定真正的问题,添加它很好的用例部分吗?
  • 还有 /orders/customers/7 和 /customers/7/orders ,我不认为这是模棱两可的原因。当然不是最好的路线。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-17
  • 1970-01-01
  • 2014-09-05
  • 2023-03-07
  • 1970-01-01
相关资源
最近更新 更多