2010-11-01 141 views
1

我对WCF没有经验,我也无法弄清楚一种无痛的方式来模拟WCF服务。WCF和嘲讽

的情况:客户端和服务器都可以访问的接口定义服务,像这样:

public interface ICustomerService 
{ 
    [OperationContract] 
    Customer GetCustomer(int id); 
} 

现在,我的第一个问题,为什么你会不想做,如果有一个理由客户端和服务器共享共享库中定义服务的相同接口类型。当然,如果服务的消费者不是.NET,或者如果您将它暴露给没有该库的第三方,但我在时共享这种可能性,伤害了其他场景,对吧?其次,如果这不是一个坏主意,我该如何真正让Visual Studio重用服务接口?我设法通过检查Re-use types来共享Customer类型,这也是在共享程序集中定义的,但它仍然会重新生成该接口。

但是,不管这些问题,我如何让客户端可以嘲笑?如果我通过VS生成的服务引用,我得到一个具体的类型来处理,但我不希望我的代码直接引用该类型,我想谈谈一个接口。如果我将生成的客户端公开为ICustomerService,这可行,我没有Close方法,因为接口没有定义它。

我还以为下面的办法和完全放弃自动生成客户端和只写客户自己当成是微不足道:

public interface IServiceClient<T> 
{ 
    void Close(); 
    T Services { get; } 
} 

public class CustomerServiceClient : ClientBase<ICustomerService>, ICustomerService, IServiceClient<ICustomerService> 
{ 
    public Customer GetCustomer(int id) 
    { 
     return base.Channel.GetCustomer(id); 
    } 

    public ICustomerService Services 
    { 
     get { return this; } 
    } 
} 

这工作,我可以公开为IServiceClient<ICustomerService>我IoC容器,但要注意的是现在是client.Services.GetCustomer(1),并且当ICustomerService界面更改时,我已经失去了轻松重新生成客户端的好处。这是微不足道的代码添加,但可能仍然很烦人,以保持这一点。

另一种可能性是利用生成的类为partial的事实。它也适用于我这样做:

interface ICloseable 
{ 
    void Close(); 
} 

interface ClientInterface : ICustomerService, ICloseable 
{ 
} 

partial class CustomerServiceClient : IClientInterface 
{ 

} 

但是,这造成了一个虚假的类和接口,这不是一场灾难,但不是很漂亮。

在我走下任一条路线之前,有没有什么明显的我忽略了?

+0

这里有一个非常类似的问题:http://stackoverflow.com/questions/4030475/integration-testing-web-services-against-a-testing-database – 2010-11-02 07:03:23

回答

0

如果你使用Windsor作为你的IoC(不知道Unity是什么),你可以得到它来注入一个WCF客户端。这意味着你的消费代码只需要担心ICustomerService。

container = new WindsorContainer().AddFacility<WcfFacility>(); 

container.Register(Component 
    .For<ICustomerService>() 
    .ActAs(DefaultClientModel 
    .On(WcfEndpoint.FromConfiguration("CustomerService"))) 
    .LifeStyle.Transient); 
+0

是的,但问题在于'ICustomerService'没有定义'Close'方法,我不想定义它,因为它的服务器实现不需要'Close'方法。我使用Ninject作为IoC btw。 – JulianR 2010-11-01 18:33:43

+0

你不需要温莎将通过WcfFacility为你照顾。它知道它实现了IDisposable – Bronumski 2010-11-01 18:38:43

+0

从我听到的大多数事情来看,通常不推荐“Dispose”WCF客户端,因为在Dispose期间发生的任何错误(关闭连接)都将被隐藏。 – JulianR 2010-11-01 22:34:44

0

不,在单个程序集中共享接口不会损害您的非管理客户端的前景。别担心。

至于另一条路线 - 我没有使用嘲笑框架,但我想知道其中的一个可能会有所帮助。那就是说,你有没有考虑过将你的测试需求从“单元测试”提升到“集成测试”?我一直在测试我的WCF服务的方式是让一个假客户端使用一个真正的WCF客户端存根,然后使用真实的服务器,并且真正的服务器正在与假的服务器控制器通信。然后我运行客户端和服务器进程 - 在一个进程中使用appdomain magic。该单个进程在Visual Studio的单元测试框架的上下文中运行。所以我正在运行集成测试,就好像它们是单元测试一样。非常好!

0

自动生成客户端通常仅适用于您无法在客户端和服务器之间共享代码的情况。它为你生成新的类型。

共享合同(即接口和它使用的DataContract类型)的正确方法是在单独的程序集中定义这些类型,该程序集应分发给服务器和客户端。然后,您可以在服务器上实现服务器实施,并在客户端上实现服务器上的客户端实施

当你有类型可用时,很容易创建自己的客户端实现,就像你发现自己一样。这通常是我会做的。这也可以很容易地模拟和/或注入服务实现。

如果您没有选择在客户端和服务器之间共享合同组件,最好的做法是利用部分生成的类来添加接口和Close方法。

+0

谢谢,但是有没有更简单的方法来编写一个客户端,该客户端既拥有该服务的'ICustomerService'方法,又有需要运行的客户端的东西(比如'Close'方法)? 'IServiceClient '的例子是我能想到的最优雅的。 – JulianR 2010-11-01 18:36:50