【发布时间】:2016-09-29 10:24:29
【问题描述】:
我对 ServiceStack 的“旧”和“新”API 有点困惑,需要一些说明和最佳实践,尤其是请求/响应 DTO 和路由。我在 Pluralsight 上观看了一些课程,并在我的电子书架上列出了 servicestack.net 上的前三本书。
我喜欢对使用 DDD 模式 构建的现有应用程序进行“重构”,这意味着我具有高级别的抽象。客户端是 WPF,遵循 MVVM 模式。我有“客户端服务”、“服务器端服务”和存储库类(还有一些聚合)。我使用 NHibernate 4(具有流畅的 API 和代码优先方法)作为 ORM。只有我的存储库类知道 ORM。我的所有实体对象都有 DTO,在我的 WPF 客户端中,我只使用 ViewModel 类中的那些 DTO。我大量使用 AutoMapper 将实体对象“传输”到我的 DTO,反之亦然。
我的困惑正是从这些 DTO 和 ServiceStack 中使用的请求/响应 DTO 开始的。这是一个非常简化的地址实体示例,它说明了问题:
我所有的实体对象都派生自 EntityBase,它包含所有实体中使用的基本属性:
public abstract class EntityBase : IEntity
{
public virtual Guid Id { get; protected set; }
public virtual DateTime CDate { get; set; } //creation date
public virtual string CUser { get; set; } //creation user
public virtual DateTime MDate { get; set; } //last modification date
public virtual string MUser { get; set; } //last modification user
//
// some operators and helper methods irrelevant for the question
// ....
}
public class Address : EntityBase
{
public string Street { get; private set; }
public string AdrInfo1 { get; private set; }
public string AdrInfo2 { get; private set; }
public string ZipCode { get; private set; }
public string City { get; private set; }
public string Country { get; private set; }
}
当然,这里忽略了相关对象的集合和引用以及数据库映射器、命名约定等。我拥有的 DTO 如下所示:
public class AddressDto
{
public Guid Id { get; set; } // NHibernate GUID.comb, NO autoincrement ints!!
public DateTime CDate { get; set; }
public string CUser { get; set; }
public DateTime MDate { get; set; }
public string MUser { get; set; }
public string Street { get; private set; }
public string AdrInfo1 { get; private set; }
public string AdrInfo2 { get; private set; }
public string ZipCode { get; private set; }
public string City { get; private set; }
public string Country { get; private set; }
}
要将它与 ServiceStack 一起使用,我需要支持以下内容:
- CRUD 功能
- 过滤/搜索功能
所以我的“地址服务”应该有以下方法:
- GetAddresses(ALL、ById、ByZip、ByCountry、ByCity)
- AddAddress(没有 Id.CDate、CUser 的完整 AddressDTO 会自动填写,无需用户输入)
- UpdateAddress(无需用户输入即可自动填写无 CUser 和 CDate、MDate 和 MUser 的完整 AddressDTO)
- 删除地址(仅 ID)
对我来说很清楚,所有请求都返回单个 AddressDto 或 List<AddressDto> 作为 ResponseDTO,但删除应该只返回一个状态对象。
但是如何定义所有的 RequestDTO 呢?我真的必须为每个场景定义一个 DTO 吗?? 在书中我只看到了以下示例:
[Route("/addresses", "GET")]
public class GetAddresses : IReturn<AddressesResponse> { }
[Route("/addresses/{Id}", "GET")]
public class GetAddressById : IReturn<AddressResponse>
{
public Guid Id { get; set; }
}
[Route("/addresses/{City}", "GET")]
public class GetAddressByCity : IReturn<AddressResponse>
{
public string City { get; set; }
}
// .... etc.
这是很多样板代码,让我想起了我在 C++ 和 CORBA 中使用的很多旧 IDL 编译器.....
特别是对于创建和更新,我应该能够“共享”一个 DTO,甚至更好地重用我现有的 DTO...对于删除,可能没有太多选择......
然后是过滤器。我还有其他具有更多属性的 DTO。像在 WCF、RPC 等中使用的函数方法是地狱编码...... 在我的存储库中,我传递了一个完整的 DTO 并使用了一个谓词构建器类,该类根据填充的属性组成 LINQ where 子句。这看起来像这样:
List<AddressDto> addresses;
Expression<Func<Address, bool>> filter = PredicateBuilder.True<Address>();
if (!string.IsNullOrEmpty(address.Zip))
filter = filter.And(s => s.Zip == address.Zip);
// .... etc check all properties and dynamically build the filter
addresses = NhSession.Query<Address>()
.Where(filter)
.Select(a => new AddressDto
{
Id = a.Id,
CDate = a.CDate,
//.... etc
}).ToList();
我可以用我的 RequestDTO 做任何类似的事情吗?应该如何定义路由?
【问题讨论】:
标签: servicestack