我正在开发一个 WCF 项目,我想在其中实现一个 RICH 域模型,其中客户端对象充当服务器端功能的远程外观,但在客户端/服务器之间具有某些共享方面,例如验证。假设我有一个包含两个方法的 Order 类:Save() 和 Submit()。在服务器上,Save() 方法将写入数据库,而 Submit() 方法会将订单发送到供应商的系统。
我想在客户端镜像富域模型,但我不想在 Save() 方法中写入数据库,而是想运行验证代码,然后在 WCF 服务接口(interface)上调用 SaveOrder(this)。这将遵循 Fowler 的服务层 + 域模型模式。理想情况下,我想编写一个 AbstractOrder 基类,实现所有共享功能并指定抽象函数,然后实现一个 ClientOrder、一个 ServerOrder 和一个充当服务服务器的 WCF 接口(interface) IOrderService(with Save(AbstractOrder) and Submit(AbstractOrder)) -边。 ClientOrder 的 Save()/Submit() 将调用 IOrderService 上的 Save/Submit 方法,并在方法调用期间传递自身。
有没有办法指示 WCF 将内容实例化和反序列化到哪些对象中?我特别想在我的整个应用程序中使用对象的抽象版本,并且只有在反序列化时才确定我是否需要对象的客户端/服务器端版本?我们已经自定义了 WCF 通信 channel :我们使用 protobuf 结合 gzip 压缩在客户端/服务器和 Ninject 之间传输数据以进行服务实例化。理想情况下,我想将对象实例化卸载到 Ninject。
我特别不希望 Order 类成为 WCF 服务,因为我正在处理一个相当胖的客户端,其中需要大量逻辑来保持系统在设定限制内执行,我最好不希望最终得到一个贫血的领域模型,其中大部分逻辑都塞进了服务中。
在代码中它会像这样:
[ServiceContract]
public interface IOrderService
{
[OperationContract]
AbstractOrder GetById(int id);
[OperationContract]
IEnumerable<AbstractOrder> GetBySupplier(int supplierId);
[OperationContract]
void Save(AbstractOrder order);
[OperationContract]
void Submit(AbstractOrder order);
}
public abstract class AbstractOrder()
{
public int Id { get; set; }
public string Description { get; set; }
public List<AbstractOrderline> OrderLines { get; set; }
public abstract void Save();
public abstract void Submit();
}
public class ClientOrder : AbstractOrder
{
public override void Save()
{
ValidateOrThrow();
_service.Save(this);
}
public override void Submit()
{
ValidateOrThrow();
_service.Submit(this);
}
}
public class ServerOrder : AbstractOrder
{
public override void Save()
{
ValidateOrThrow();
_unitOfWork.Save(this);
}
public override void Submit()
{
Save();
_supplierOrderService.Submit(this);
}
}
最佳答案
默认情况下你不能这样做:
// Interface
AbstractOrder IOrderService.GetById(int);
// Service
AbstractOrder OrderService.GetById(int id)
{
return new ServiceOrder(...);
}
// Client
ClientOrder = (ClientOrder)IOrderService.GetById(42);
因为服务返回的顺序不是 ClientOrder
.使用一些反射和 custom formatter你应该能够走很长的路。
或者,您可以依赖组合,而不是继承。介绍一个IRepository<T>
(或给它起个名字)在你的共享代码中,并在你的模型上为它创建一个属性:
public interface IRepository<T>
{
void Save(T model);
void Submit(T model);
}
public class Order()
{
public int Id { get; set; }
public string Description { get; set; }
public List<AbstractOrderline> OrderLines { get; set; }
[XmlIgnore]
public IRepository<Order> Repository { get; set; }
public void Save()
{
if (Repository == null) { throw new NotSupportedException(); }
Repository.Save(this);
}
public void Submit()
{
if (Repository == null) { throw new NotSupportedException(); }
Repository.Submit(this);
}
}
现在您可以通过此存储库将特定于服务或客户端的逻辑注入(inject)到您的模型中:
// Client-specific implementation
public class ClientOrderRepository : IRepository<Order>
{
private readonly IClientOrderService _service;
public ClientOrderRepository(IClientOrderService clientOrderService)
{
_service = clientOrderService;
}
public void Save(Order order)
{
_service.Save(order);
}
public void Submit(Order order)
{
_service.Submit(order);
}
}
然后你的服务和客户端看起来像这样:
// Interface
Order IOrderService.GetById(int);
// Service
Order OrderService.GetById(int id)
{
return new Order(...);
}
// Client
Order order = IOrderService.GetById(42);
order.Repository = new ClientRepository(...);
order.Submit();
关于c# - 在 WCF 中实现丰富的域模型,其中客户端对象充当远程外观,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34087268/