c# - 在 WCF 中实现丰富的域模型,其中客户端对象充当远程外观

标签 c# .net wcf architecture

我正在开发一个 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/

相关文章:

c# - EF 6.0 中缺少 DbSet<entity>.Load() 函数

c# - 试图找出模型和 DbContext : 'Employee' 的 EntityFramework 元数据

c# - C#/C++ 中缓存或预计算的不可变函数

.net - EF4 + MVVM - 在 ViewModel 中公开实体?

c# - 序列化包含 StateServer 的 linq2sql 对象的对象

c# - 请求期间使用 WCF 的 System.OutOfMemoryException

c# - WCF 数据服务 $filter 在日期时间之间进行搜索

c# - 客户端 - 服务器或网络服务?

c# - 试图了解静态在这种情况下是如何工作的

c# - ASP.NET 图表和用户控制输出缓存