实施WCF丰富的域模型,其中客户端对象充当远程外观 [英] Implementing a rich domain model in WCF where the Client objects act as remote facades

查看:107
本文介绍了实施WCF丰富的域模型,其中客户端对象充当远程外观的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作,我想实现当客户端对象充当服务器端的功能,但客户端/服务器之间共享的某些方面,比如验证远程外观丰富的域模型一个WCF项目。比方说,我有一个Order类有两个方法:save()和提交()。在服务器中保存()方法将写入数据库,并提交()将命令发送到供应商的系统。

我想反映在客户端上丰富的域模型,但不是在保存()方法做一个数据库写,我想运行验证code,然后WCF服务接口调用SaveOrder(本)。这将遵循Fowler的服务层+领域模型模式。理想的情况是我想写一个AbstractOrder基类,实现所有共享功能,并指定抽象函数,然后实施ClientOrder,一个ServerOrder和WCF接口IOrderService(与保存(AbstractOrder),并提交(AbstractOrder)),它充当业务服务器-侧。该ClientOrder的保存()/提交()将调用Save /提交关于IOrderService方法和方法调用过程中传递本身。

有没有一种方法来指示WCF的对象实例化和反序列化内容转换成?我特别希望在我的整个应用程序的工作与对象的摘要版本,只有在反序列化弄清楚我是否需​​要对象的客户端/服务器端版本?我们已经定制了WCF沟通渠道:我们使用的protobuf用gzip COM pression客户端/服务器和Ninject服务实例之间的数据传输相结合。理想我想卸载对象实例化Ninject。

我特别不希望Order类是一个WCF服务,因为我处理一个相当胖客户端在需要大量逻辑来保持系统设定的范围内执行和我preferably唐不想与大多数逻辑被塞进服务贫血的域模型就结了。

在code这将是这样的:

  [的ServiceContract]
公共接口IOrderService
{
    [OperationContract的]
    AbstractOrder GetById(中间体ID);
    [OperationContract的]
    IEnumerable的< AbstractOrder> GetBySupplier(INT供应商ID);
    [OperationContract的]
    无效保存(AbstractOrder顺序);
    [OperationContract的]
    无效提交(AbstractOrder顺序);
}公共抽象类AbstractOrder()
{
    公众诠释标识{搞定;组; }
    公共字符串描述{搞定;组; }
    公开名单< AbstractOrderline> OrderLines {搞定;组; }    公共抽象无效保存();
    公共抽象无效提交();
}公共类ClientOrder:AbstractOrder
{
    公共覆盖无效保存()
    {
        ValidateOrThrow();
        _service.Save(本);
    }    公共覆盖无效提交()
    {
        ValidateOrThrow();
        _service.Submit(本);
    }
}公共类ServerOrder:AbstractOrder
{
    公共覆盖无效保存()
    {
        ValidateOrThrow();
        _unitOfWork.Save(本);
    }    公共覆盖无效提交()
    {
        保存();        _supplierOrderService.Submit(本);
    }
}


解决方案

在默认情况下,你不能做到这一点:

  //接口
AbstractOrder IOrderService.GetById(INT);//服务
AbstractOrder OrderService.GetById(INT ID)
{
    返回新ServiceOrder(...);
}//客户端
ClientOrder =(ClientOrder)IOrderService.GetById(42);

由于该服务返回的的顺序并不的一个 ClientOrder 。使用一些反思和<一个href=\"https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.iclientmessageformatter(v=vs.110).aspx\"相对=nofollow>自定义格式你应该能够很长的路要走。

另外,你可以依靠组成,而不是继承。引入 IRepository&LT; T&gt;在您的共享code (或给它一个名称),并为你的模型创建一个属性:

 公共接口IRepository&LT; T&GT;
{
    无效保存(T型);
    提交无效(T模式);
}公共类订单()
{
    公众诠释标识{搞定;组; }
    公共字符串描述{搞定;组; }
    公开名单&LT; AbstractOrderline&GT; OrderLines {搞定;组; }    [XmlIgnore]
    公共IRepository&LT;排序&gt;存储库{搞定;组; }    公共无效保存()
    {
        如果(库== NULL){抛出新NotSupportedException异常(); }
        Repository.Save(本);
    }    公共无效提交()
    {
        如果(库== NULL){抛出新NotSupportedException异常(); }
        Repository.Submit(本);
    }
}

现在你可以注入thorugh这个仓库的服务 - 或者客户特定的逻辑到模型:

  //客户特定的实现
公共类ClientOrderRepository:IRepository&LT;排序&gt;
{
    私人只读IClientOrderService _service;
    公共ClientOrderRepository(IClientOrderService clientOrderService)
    {
        _Service = clientOrderService;
    }    公共无效保存(订购订购)
    {
        _service.Save(订单);
    }    公共无效提交(订单顺序)
    {
        _service.Submit(订单);
    }
}

然后,你的服务和客户端是这样的:

  //接口
为了IOrderService.GetById(INT);//服务
为了OrderService.GetById(INT ID)
{
    返回新订单(...);
}//客户端
订购订购= IOrderService.GetById(42);
order.Repository =新ClientRepository(...);
order.Submit();

I'm working on a WCF project where I want to implement a RICH domain model where the client-side objects act as remote facades for server-side functionality but with certain shared aspects between client/server, such as validation. Let's say I have an Order class with two methods: Save() and Submit(). On the Server the Save() method would write to the database and the Submit() would send the order to a supplier's system.

I want to mirror the rich domain model on the client but instead of doing a database write in the Save() method, I want run the validation code and then call SaveOrder(this) on a WCF service interface. This would follow Fowler's Service layer + Domain model patterns. Ideally I want to write an AbstractOrder base class, implementing all shared functionality and specifying the abstract functions and then implement a ClientOrder, a ServerOrder and a WCF interface IOrderService(with Save(AbstractOrder) and Submit(AbstractOrder)) which acts as the service server-side. The ClientOrder's Save() / Submit() would call the Save/Submit methods on the IOrderService and pass itself during method call.

Is there a way to instruct WCF which objects to instantiate and deserialize the content into? I specifically want to work throughout my entire application with the Abstract version of the object and only upon deserialization figure out whether I need the Client/Server-side version of the object? We've already customized the WCF communication channels: we use protobuf combined with gzip compression for data transport between client/server and Ninject for service instantiation. Ideally I want to offload object instantiation to Ninject.

I specifically don't want the Order class to be a WCF service because I'm dealing with a fairly fat client where a large amount of logic is needed to keep the system perform within set limits and I preferably don't want to end up with an anemic domain model where most logic is stuffed into services.

In code it would like this:

[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);
    }
}

解决方案

By default you cannot do this:

// Interface
AbstractOrder IOrderService.GetById(int);

// Service
AbstractOrder OrderService.GetById(int id)
{
    return new ServiceOrder(...);
}

// Client
ClientOrder = (ClientOrder)IOrderService.GetById(42);

Because the order that the service returns is not a ClientOrder. Using some reflection and a custom formatter you should be able to come a long way.

Alternatively, you could rely on composition, not inheritance. Introduce an IRepository<T> (or give it a name) in your shared code and create a property for that on your model:

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);
    }
}

Now you can inject the service- or client-specific logic thorugh this repository into your model:

// 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);
    }
}

Then your service and client look like this:

// 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();

这篇关于实施WCF丰富的域模型,其中客户端对象充当远程外观的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆