2010-11-01 152 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