ServiceStack客户端和不明确的路由

时间:2013-12-15 02:21:08

标签: web-services rest routes servicestack

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

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

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

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

这可以在浏览器中点击路径时找到,但是当我使用ServiceStack客户端时,我得到了不明确的路由异常,并列出了三条路由。

我不太确定这方面最好的方法是什么......我正在做的不是正确的REST方式吗?

我知道我可以简单地手动输入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;
   }
}

我是否必须为此使用不同的Dt或......?

任何有关此方法的示例的任何帮助或指示,或者更好的方式来创建服务将不胜感激。

由于

1 个答案:

答案 0 :(得分:7)

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

了解您的用例:

在您的具体案例中,如果我们查看/orders/customers/7这会更好用,您会这样想:

  

/客户/ 7 /订单

你这样做的原因:

  • 它解决了您的路线歧义问题
  • 背景清楚。我们可以看到我们正在使用 Customer 7 而无需导航长网址
  • 我们可以看到'与客户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