我一直在寻找基于消息的服务(ServiceStack风格)并远离WCF风格的服务(几乎是RPC)。从使用WCF风格的服务,我看到一些缺点,我想尝试另一种方法。它让我觉得WCF方法不能真正有重载,我理解为什么,我知道有很多方法可以解决它,但那些让我觉得很烦。基于消息的服务承认事情已经过时。
我遇到的问题是如何处理检索数据。 ServiceStack(和其他API)似乎有一个请求对象,用于获取单个实体或实体集合。此请求对象具有许多可选参数。例如
public GetInvoiceRequest
{
public int? InvoiceId {get; set;}
public int? AccountId {get; set;}
public DateTime? From {get; set;}
}
public GetInvoiceResponse
{
public List<InvoiceDto> {get;set;}
public ResponseStatus Status {get;set;}
}
此类事物的标准做法是什么?您是否包含每个可选参数的发票?因此,您获得了ID的发票,然后如果还设置了AccountId,则添加该帐户的所有发票,如果还设置了From,则添加特定日期的所有发票?有效地执行工会。或者你执行这些集合的交集?或者您只是尊重设置的第一个参数。因此,如果设置了所有参数,则只返回与InvoiceId匹配的Invoice,因为这是遇到的第一个参数?
答案 0 :(得分:3)
您有正确的想法,并且您的方法是有效的,但人们倾向于将请求特定发票的意图与发票清单请求分开。
我倾向于建立一种服务,使我的DTO遵循C-R-U-D-L操作格式,即。创建读取更新删除列表键入DTO:
所以当我有一个ReadInvoiceRequest
而不是GetInvoiceRequest
时,我知道将始终返回一个InvoiceDto
对象,并且需要InvoiceId
参数:
[Route("/invoices/{InvoiceId}", "GET")]
[Route("/account/{AccountId}/invoices/{InvoiceId}","GET")]
public ReadInvoiceRequest : IReturn<InvoiceDto>
{
public int InvoiceId { get; set; } // InvoiceId is always expected
public int? AccountId { get; set; }
public DateTime? From { get; set; }
}
专门用于列表的路线将始终返回InvoiceDto
:
[Route("/invoices", "GET")]
[Route("/account/{AccountId}/invoices","GET")]
public ListInvoicesRequest : IReturn<List<InvoiceDto>>
{
public int? AccountId { get; set; }
public DateTime? From { get; set; }
}
如果指定了InvoiceId
并且您的返回类型是结果列表,则可以防止返回多少结果的模糊性。
这也使消费者明白请求DTO中的可选参数将被视为过滤器。
您服务中的操作方法将与此类似:
public class MyInvoiceService : Service
{
// CREATE
public int Post(CreateInvoiceRequest request)
{
// Return the InvoiceId of the created record
}
// READ
public InvoiceDto Get(ReadInvoiceRequest request)
{
var invoice = ... // request.InvoiceId; (filter by AccountId & From if set)
return invoice;
}
// UPDATE
public void Post(UpdateInvoiceRequest request)
{
// Handle update
// I don't return anything, only throw exceptions if update fails
// Success is indicated by 200 status
}
// DELETE
public void Delete(DeleteInvoiceRequest request)
{
// Handle delete
// I don't return anything, only throw exceptions if delete fails
// Success is indicated by 200 status
}
// LIST
public List<InvoiceDto> Get(ListInvoicesRequest request)
{
var invoices = ... // (filter by AccountId & From if set)
return invoices;
}
}
从服务消费者的角度来看,我认为从分离的DTO中获得的回应不确定性较低。
答案 1 :(得分:1)
ServiceStack API已从一个Request和匹配的Response DTO模式转移。 ServiceStack现在允许许多不同的请求DTO以及明确指定响应对象的能力。
你应该看到这个答案:ServiceStack Request DTO design
但通常在执行搜索时我会使用可选(可空)属性并动态生成搜索查询。