同樣是呼叫第三方 web service 時碰到的狀況:Visual Studio 產生的 proxy 類別的每個屬性名稱後面都多加了 "Field",例如:CustomerIdField、CompanyField 等等。先說解法:在定義 WCF 服務的介面時,為每個介面方法套用 XmlSerializeFormatAttribute 就行了。
(以下是細節描述,純粹記錄,除非你也碰到同樣問題,否則無須細讀。)
問題:Visual Studio 產生的 WCF 用戶端 proxy 類別的屬性名稱會多加 "Field"。
得先說一下,之所以會出現這種狀況,是因為有兩層 web services,像這樣:
WCF 用戶端 app ----------> MyWrapperService -----------> 第三方 Java web service
基於某些原因,用戶端 app 不能直接呼叫第三方 web service,而得透過中間的 MyWrapperService 來轉呼叫。MyWrapperService 是個 WCF service,單純作為轉接器,是第三方 web service 的拷貝。
也就是說,在 MyWrapperService 專案中,除了定義自己的服務介面供用戶端呼叫,還會有一個對應至第三方 web service 的 proxy 類別。基本上,MyWrapperService 幾乎完全複製了第三方 web service 的服務介面,其中包括用來當作傳入參數或傳回值的自訂複雜型別也都一樣。
還是補張圖,比較清楚:
在 MyWrapperService 專案中,查看 Visual Studio(SvcUtilexe)為第三方 web service 產生的 proxy 類別的原始碼(Reference.cs),可以發現其私有欄位名稱都會額外加上 "Field" 字樣,例如 customerIdField,公開屬性的名稱則維持原樣,例如 customerId。底下是個範例:
這沒問題,只要公開屬性的名稱與原本 web service 中的屬性名稱一樣就好。
然後,在 MyWrapperService 中定義服務介面,這個介面會與第三方 web service 的介面長得很像:
其中的 Party3.Services.GetCustomerResponse 型別就是上一個範例中的那個第三方 web service 的 proxy 類別中的一個回傳型別。
中間的轉接器寫完了,接著要寫用戶端程式。然而在用戶端應用程式專案中使用 Visual Studio 的「Add Service Reference」來產生 MyWrapperService 的 proxy 類別時,卻發現產生出來的 proxy 類別裡面的屬性名稱都會多加上 "Field",而屬性所對應的私有欄位名稱則是變成加倍的 "FieldField"。例如前面的 GetCustomerResponse 型別,經由工具產生對應的 proxy 之後,會變成這樣:
如此一來,在撰寫用戶端程式時,與該服務相關的所有型別的公開屬性名稱後面就得加上額外的 "Field",這已經和原始 web service 中定義的屬性名稱不同,雖然可以編譯,也可以執行,但看著實在彆扭。
原因:ServiceModel Metadata Utility (SvcUtil.exe) 工具的預設行為(這表示其實我不知道真正原因 XD)。
解法:在欲呼叫的目標 WCF 服務的介面中為每個方法套用 [XmlSerializeFormatAttribute]。
像這樣:
就行了。
參考資料
(以下是細節描述,純粹記錄,除非你也碰到同樣問題,否則無須細讀。)
問題:Visual Studio 產生的 WCF 用戶端 proxy 類別的屬性名稱會多加 "Field"。
得先說一下,之所以會出現這種狀況,是因為有兩層 web services,像這樣:
WCF 用戶端 app ----------> MyWrapperService -----------> 第三方 Java web service
基於某些原因,用戶端 app 不能直接呼叫第三方 web service,而得透過中間的 MyWrapperService 來轉呼叫。MyWrapperService 是個 WCF service,單純作為轉接器,是第三方 web service 的拷貝。
也就是說,在 MyWrapperService 專案中,除了定義自己的服務介面供用戶端呼叫,還會有一個對應至第三方 web service 的 proxy 類別。基本上,MyWrapperService 幾乎完全複製了第三方 web service 的服務介面,其中包括用來當作傳入參數或傳回值的自訂複雜型別也都一樣。
還是補張圖,比較清楚:
在 MyWrapperService 專案中,查看 Visual Studio(SvcUtilexe)為第三方 web service 產生的 proxy 類別的原始碼(Reference.cs),可以發現其私有欄位名稱都會額外加上 "Field" 字樣,例如 customerIdField,公開屬性的名稱則維持原樣,例如 customerId。底下是個範例:
public partial class GetCustomerResponse : object, System.ComponentModel.INotifyPropertyChanged { private int customerIdField; [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=0)] public int customerId { get { return this.customerIdField; } set { this.customerIdField = value; this.RaisePropertyChanged("customerId"); } } }
這沒問題,只要公開屬性的名稱與原本 web service 中的屬性名稱一樣就好。
然後,在 MyWrapperService 中定義服務介面,這個介面會與第三方 web service 的介面長得很像:
[ServiceContract] public interface IMyWrapperService { [OperationContract] Party3.Services.GetCustomerResponse GetCustomer(int id); }
其中的 Party3.Services.GetCustomerResponse 型別就是上一個範例中的那個第三方 web service 的 proxy 類別中的一個回傳型別。
中間的轉接器寫完了,接著要寫用戶端程式。然而在用戶端應用程式專案中使用 Visual Studio 的「Add Service Reference」來產生 MyWrapperService 的 proxy 類別時,卻發現產生出來的 proxy 類別裡面的屬性名稱都會多加上 "Field",而屬性所對應的私有欄位名稱則是變成加倍的 "FieldField"。例如前面的 GetCustomerResponse 型別,經由工具產生對應的 proxy 之後,會變成這樣:
public partial class GetCustomerResponse : object, System.ComponentModel.INotifyPropertyChanged { private int customerIdFieldField; // 私有欄位名稱變成 "xxFieldField" [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, Order=0)] public int customerIdField // 公開屬性名稱額外加了 "Field" { get { return this.customerIdFieldField; } set { this.customerIdFieldField = value; this.RaisePropertyChanged("customerIdField"); } } }
原因:ServiceModel Metadata Utility (SvcUtil.exe) 工具的預設行為(這表示其實我不知道真正原因 XD)。
解法:在欲呼叫的目標 WCF 服務的介面中為每個方法套用 [XmlSerializeFormatAttribute]。
像這樣:
[ServiceContract] public interface IMyWrapperService { [XmlSerializerFormat] [OperationContract] GetCustomerResponse GetCustomer(int id); }
就行了。
參考資料
沒有留言: