传说中的WCF(6):数据协定(b)
我們繼續,上一回我們了解了數據協定的一部分內容,今天我們接著來做實驗。好的,實驗之前先說一句:實驗有風險,寫代碼須謹慎。
實驗開始!現在,我們定義兩個帶數據協定的類——Student和AddrInfo。
[DataContract]public class Student{[DataMember]public string Name;[DataMember]public string Phone;[DataMember]public AddrInfo Address;} [DataContract]public class AddrInfo{[DataMember]public string Province;[DataMember]public string City;[DataMember]public string DetailAddr;}
這兩個類有一個特征,Student類的Address字段是一個AddrInfo對象,而我們的服務定義如下:
方法返回的Student對象,那么,我們來測試一下,AddrInfo能不能被成功序列化和反序列化。下面是注冊和啟動服務的代碼:
static void Main(string[] args){// 服務器基址Uri baseAddress = new Uri("http://localhost:1378/services");// 聲明服務器主機using (ServiceHost host = new ServiceHost(typeof(MyService), baseAddress)){// 添加綁定和終結點WSHttpBinding binding = new WSHttpBinding();host.AddServiceEndpoint(typeof(IService), binding, "/test");// 添加服務描述host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });try{// 打開服務host.Open();Console.WriteLine("服務已啟動。");}catch (Exception ex){Console.WriteLine(ex.Message);}Console.ReadKey();}}在客戶端生成的代碼中,兩個類都可以正確生成。
客戶端測試代碼如下:
static void Main(string[] args){WS.ServiceClient cli = new WS.ServiceClient();WS.Student stu = cli.GetStudentInfo();string msg = "學生姓名:{0}\n聯系電話:{1}\n" +"地址信息:-----------\n" +"省份:{2}\n" +"市區:{3}\n" +"詳細地址:{4}";Console.WriteLine(msg, stu.Name, stu.Phone, stu.Address.Province, stu.Address.City, stu.Address.DetailAddr);Console.ReadKey();}
其運行結果如下:
?
?
下面我們繼續實驗。
每個學生可能有多個學科的成績,因此,我們為學生類再添加一個成績屬性。
[DataContract]public class Student{[DataMember]public string Name;[DataMember]public string Phone;[DataMember]public AddrInfo Address;[DataMember]public object Scores;} public class MyService : IService{public Student GetStudentInfo(){Student stu = new Student();AddrInfo info = new AddrInfo();info.Province = "廣東省";info.City = "佛山市";info.DetailAddr = "火星路-300號";stu.Name = "小陳";stu.Phone = "1388888888";stu.Address = info;Dictionary<string, float> m_scores = new Dictionary<string, float>();m_scores.Add("語文", 97f);m_scores.Add("英語", 64.5f);m_scores.Add("數學", 38f);m_scores.Add("歷史", 77.6f);m_scores.Add("地理", 82.3f);stu.Scores = m_scores;return stu;}}
客戶端測試代碼改為:
現在來測試,就會發生異常,因為我們為Student類加的成績屬性是object類型,而我們在協定方法中給它賦的是 Dictionary<string, float>類型,這樣一來,就算可以序列化也不能被反序列化,因為Dictionary<string, float>無法識別。
現在,我們再為Student類添加一個KnownType特性,看它能不能識別。
[DataContract]
[KnownType(typeof(Dictionary<string, float>))]
public class Student
{
。。。。。
}
這時候,再運行一下。
很可惜,還是報錯了,
?
怎么辦呢?不要放棄,我們繼續把學生類修改一下。
[DataContract][KnownType("GetKnowTypes")]public class Student{[DataMember]public string Name;[DataMember]public string Phone;[DataMember]public AddrInfo Address;[DataMember]public object Scores;static Type[] GetKnowTypes(){return new Type[] { typeof(Dictionary<string,float>) };}}GetKnowTypes方法是靜態方法,KnownType的構造函數中傳遞該方法的名字。看看這回調用能否成功?
堅持就是勝利,看到了吧,這回OK了!高興吧。
?
這里我們可以總結一下,在一些比較復雜的類型無法反序列化(不能識別類型)的時候,就得考慮使用KnownTypeAttribute來標注可能涉及到的外部類型,但如果遇到像泛型這些較為復雜的類型,就要考慮在帶數據協定的類中添加一個靜態方法,該方法返回Type 的IEnumerable,一般是Type[]就可以了,而在KnownTypeAttribute的構造函數中使用這個方法的名字。
轉載于:https://www.cnblogs.com/GoogleGetZ/p/5752323.html
總結
以上是生活随笔為你收集整理的传说中的WCF(6):数据协定(b)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HW2.12
- 下一篇: 关于启动 SecureCRT 遇到一个致