2009-08-14 21 views
1

我正在編寫客戶端/服務器應用程序,其中客戶端是Windows窗體應用程序,服務器是Windows服務中託管的WCF服務。請注意,我控制應用程序的兩側。在針對接口進行編碼時,工廠或WCF中的對象實例的依賴注入?

我想實現對接口進行編碼的做法:即我有一個由客戶端應用程序引用的共享程序集。該項目包含我的WCF ServiceContracts和接口,這些接口將暴露給客戶。我試圖只向客戶端公開接口,以便它們只依賴於合同,而不是任何特定的實現。這樣做的原因之一是,我可以隨時執行服務實施和域更改,而無需重新編譯和重新部署客戶端。在這種情況下,接口/合同不會改變。我只需要重新編譯和重新部署我的WCF服務。

我現在面臨的設計問題是:在客戶端上,如何創建對象的新實例,例如,如果客戶不知道Customer的具體實現情況如何?我需要創建一個新客戶以保存到數據庫。

我是否使用依賴注入或Factory類來實例化新對象,還是應該讓客戶端創建具體實現的新實例?

我不是在做TDD,我通常只會有一個實現ICustomer或任何其他暴露的接口。

回答

0

嗯,我想你混淆(或混淆)兩件事情:

  • 服務合同將只描述你的服務公開的功能,像FindCustomerAddCustomer - 爲那些行動,客戶端只需要知道的接口,當你添加一個客戶端代理(通過使用「添加服務引用」),你還可以得到一個YourServiceClient具體類中實現這些調用您的客戶端代理

  • 數據合同描述了數據來回,而這些數據總是具體的類 - Customer,Invoice等 - 因爲這些都是基於XML模式。這些是在服務器上定義的,並且客戶端在添加服務引用時會從服務發佈的WSDL/XSD中推斷出這些類型,並且會在客戶端上爲該數據創建具體類。這些都是不是與服務器使用完全相同的類 - 它們看起來是一樣的,它們的主要要求是它們從XML序列化和反序列化相同 - 但它們是不同的類真正(不同的.NET命名空間,最有可能)。

因此,對於你的功能,您有服務合同,你真的只需要共享一個接口 - 這是足夠的,並且客戶端會從該接口創建一個「代理類」(即YourServiceClient類)。客戶端不依賴於服務器實現或其具體的類。另一方面,被交換的數據 - 默認情況下被序列化爲XML格式 - 將始終是從WSDL/XSD中傳遞的具體類(無接口) - 再次,客戶端不依賴於服務器的類 - 只能在他們的「XML序列化指紋」上,可以這麼說。

現在我不確定這可以幫助你很多:-)但至少它有希望讓事情變得更清楚一點 - 或者沒有。

馬克

+0

@marc_s:我覺得你完全誤解我的問題。我想我應該修改它以使其更清晰。我完全理解WCF,以及你所解釋的一切。但我沒有這樣使用WCF。客戶端和服務器共享MyProject.Shared程序集,其中包含我的類型和接口(或我將稱之爲合同,但不包含[DataContract])。因此他們從同一個裝配中共享完全相同的類型。我現在用的是NetDataContractSerializer,並使用WCF模仿更接近於 – 2009-08-14 14:14:07

1

我們已經討論了在內部做這行,我們控制應用程序的兩側企業應用,爲生產力的提高,爲.NET客戶端。陪審團仍然在這一個。

然而,在討論具有一個共享庫合同(客戶端和服務之間)時通常,這將包括服務合同([的ServiceContract]),以及作爲用於實體([DataContract])任何參數服務操作。這些類型傳統上是您期望用於這些服務操作的類型混凝土

就你而言,你的DTO實現了一個接口,比如ICustomer,實現代表Customer的屬性,並且是[DataContract]。假設類型將正確地序列化到服務(使用NetDataContractSerializer),那麼我想客戶端可以提供他們想要的任何具體實現 - 服務只關心符合ICustomer的服務。

客戶端可以創建他們想要的ICustomer的具體實例:OrderingCustomer,FinanceCustomer等只要類型實現了服務ICustomer接口,如果它正確序列化,它可以想象作爲值傳遞給服務操作。例如

public class OrderingCustomer : ICustomer 
{ 
} 

我不確定您會達到零客戶端影響你的目標。如果您更改接口類型(將屬性添加到ICustomer),您的客戶端將需要重新編譯。如果你添加一個參數,即使是一個核心的.NET類型(例如int),你的客戶端也需要重新編譯。這與客戶端更新其服務引用和重新編譯的效果實際上是相同的。

但是,如果你的改變你的服務實現或行爲(例如bug修復),然後在兩種案件(共享類型或服務引​​用)的客戶將需要花費很長時間沒有做任何事情,你之間的合同而你的客戶不會改變。當然,我也想聽聽你用這個證明這個錯誤的經驗。

這種做法也將徹底殺死您與非.NET系統的互操作故事。就像我在地毯下掃描這個東西一樣,某處的某個部門會聽到你的超級服務並希望使用它......而且他們將運行一些Java堆棧,COBOL或FORTRAN ..等等。 :)

+0

你形容我試圖實現精確.Net遠程,但你還沒有回答我的問題 - 如何在客戶端上創建對象的新實例側。你顯然不能做到這一點:'ICustomer CUS =新ICustomer',你不能做到這一點無論:'ICustomer CUS =新客戶()'因爲客戶端不能夠訪問包含了'客戶大會:客戶「實施。 – 2009-08-17 13:11:50

+0

啊,我想我錯過了我的迴應中的一點!這就是我讀得太快了! :)如果客戶是服務操作的參數,則客戶必須有權訪問ICustomer。否則,他們將如何調用該服務?他們不會知道ICustomer是什麼樣的 - 他們不能僅僅在飛行中完成它,它是客戶和服務之間的二元契約。客戶不能創建自己的ICustomer實現並使用它,你必須提供它。 :) – 2009-08-17 13:38:15

+0

你又錯過了一個關鍵點。客戶端可以訪問'ICustomer',它位於共享程序集中,由客戶端和服務器引用。必須的!但是'ICustomer'是一個接口 - 並且不能實例化接口類型,如上所述。 – 2009-08-17 16:44:43

1

我在我的WCF開發中遇到過同樣的問題。事實是必須在通信的雙方上具體實施您的數據合同。那麼這些實現從哪裏來?在服務器端,實現通常是您的業務對象,所有業務邏輯等等。而且你不想在客戶端上使用這些實現 - 這將意味着將它們放入共享程序集中,並且由於多種原因,您不需要這些實現。所以客戶需要自己的,單獨的一組具體類。要麼你會自己寫,或者你會讓它們自動生成。

編寫你自己的實現是單調乏味的。因爲客戶端對象通常很簡單 - 他們真正要做的就是存儲數據 - 代碼生成可能是一種方式。在這一點上,您有幾個選擇:您可以通過添加服務引用生成基於WSDL的代碼,也可以使用某種類型的框架基於接口在運行時生成類。

這兩種方法給你的編碼對接口的好處:只要接口不發生變化,服務器和客戶端可以修改和獨立重建。在一種情況下,接口是WSDL,另一種是CLR接口,但是由於WCF基於CLR接口生成WSDL,它們確實是一樣的。就我個人而言,我喜歡添加服務引用,因爲它已經存在,並且不會爲我的項目添加任何依賴關係,但可以選擇更適合您的項目。