調用過WCF服務的同學可能都會遇到這樣的問題,同一個實體類型,不同的服務Visual Studio生成了不同的版本,例如Service1.User和Service2.User,對於C#來說,這是兩個不同的類型,Service1獲得的User是放不到Service2服務里去的。手動的屬性賦值來轉換顯然是不可取的,所以就共享類型了。
方法1,服務端和客戶端共享數據契約程序集。
這個方法最常用,也是大家最熟悉的方法,把WCF的數據契約放在一個獨立類庫里,服務端,客戶端都引用這個程序集,然后在生成WCF時,選擇重新使用引用程序集中的類型即可。
這個方法缺點很明顯,它只有在客戶端和服務端在同一個Visual Studio解決方案內才方便,否則要不斷手動更新數據契約程序集。更不用說是第三方的服務。
方法二,暴力轉換類型
這個其實不是類型共享,不過也是解決這個問題的一種手段。就是借助AutoMapper,EmitMapper這樣的類庫幫助快速轉換類型。下面是一個例子。
Money類型包含User實體和Currency枚舉和一個數字的Amount,Money的定義
[DataContract(Namespace = Consts.Namespace)] public class Money { [DataMember] public decimal Amount { get; set; } [DataMember] public Currency Currency { get; set; } [DataMember] public UserInfo User { get; set; } }
Currency:
[DataContract(Namespace = Consts.Namespace)] public enum Currency { [EnumMember] Euro, [EnumMember] Usd, [EnumMember] PoundSterling }
UserInfo:
[DataContract(Namespace = Consts.Namespace)] public class UserInfo { [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } [DataMember] public string Email { get; set; } [DataMember] public string Phone { get; set; } [DataMember] public string Id { get; set; } }
對於DepositServiceNoSharp和WithdrawalServiceNoSharp這兩個WCF服務版本的Money和User,可以這樣添加一些擴展方法
using AutoMapper; using DepositService = Client.DepositServiceNoSharp; using Client.WithdrawalServiceNoSharp; namespace Client { public static class Extensions { static Extensions() { Mapper.CreateMap<DepositService.Money, Money>(); Mapper.CreateMap<Money, DepositService.Money>(); Mapper.CreateMap<DepositService.UserInfo, UserInfo>(); Mapper.CreateMap<UserInfo, DepositService.UserInfo>(); } public static Money ToWithdrawal(this DepositService.Money money) { return Mapper.Map<DepositService.Money, Money>(money); } public static DepositService.Money ToDeposit(this Money money) { return Mapper.Map<Money, DepositService.Money>(money); } } }
然后就可以輕松轉換
var money = new Money { Amount = 1, Currency = Currency.Usd, User = new UserInfo { Email = "zhww@outlook.com", FirstName = "zhang", Id = "123", LastName = "weiwen", Phone = "110" } }; var depositMoney = money.ToDeposit();
方法三,使用SvcMap實現類型共享
其實這個才是文章的重點,前面可以忽略。
生成第一個WCF服務后,點擊”顯示所有文件“去編輯SvcMap文件:
找到MetadataSources節點,原來只有一個,現在把其他要引用的服務添加到這里,例如:
<MetadataSources> <MetadataSource Address="http://localhost:34875/DepositService.svc" Protocol="http" SourceId="1" /> <MetadataSource Address="http://localhost:34875/WithdrawalService.svc" Protocol="http" SourceId="2" /> </MetadataSources>
再右擊服務,”更新服務引用“,所有服務都會生成到同一個命名空間里,實現類型共享。
最后感謝原作者,原文鏈接。
還有順道向微軟出示一下中指,把這個功能隱藏得這么深。
The End!