WCF学习(五)数据契约之已知类型
準備技術:
?????1.C#基礎知識
?????2.了解WCF基礎知識
?
?
?????在正常的c#開發中我們是允許用子類去替換基類的,這也是所謂的替換原則。但是我們在WCF中確不能用數據契約的子類來替換父類的,因為這中間存在一個序列化的問題。舉個例子:
?????我們有數據契約:
??????????[DataContract]
??????????class Employee{...}
?????服務契約中:
??????????[ServiceContract]
??????????interface IEmployeeManager
??????????{
???????????????[OperationContract]
???????????????void AddEmployee(Employee employee);
??????????}
?????然后我們在客戶端的代理中就算有類:Intern繼承于
??????????[DataContract]
??????????class Intern:Employee{...}
?????然后再客戶端調用時:
??????????proxy.AddEmployee(new Intern())是會出錯的。因為在服務器端無法識別Intern對象,因為他無法去反序列化Intern成Employee對象(WCF序列化)。
?????
?????
?????WCF提供給我們了一個解決的辦法就是使用KnownTypeAttribute特性,在基類上標識對應的子類就可以了。KnownTypeAttribute特性可以使用在Struct跟Class上。示例:
??????????[DataContract]
??????????[KnownType(typeof(Customer))]
??????????class Employee{...}
??????????
??????????[DataContract]
??????????class Intern:Employee{...}
這樣我們就在所有的契約跟操作上,能跨越所有的服務和終結點,允許服務接受子類。但是這樣會遇到一個問題,我們不能去特定的指定某一個服務操作,所以KnownType的缺陷就是范圍過于廣泛。WCF提供了另外一個Attribute--ServiceKnownType.
?
ServiceKnownType 特性
?????KnownType只能應用在數據契約的基類上,而ServiceKnownType可以在Interface、Method、Class上標識。看一個示例Employee.cs:
?
Codeusing?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
using?System.ServiceModel;
using?System.Runtime.Serialization;
namespace?HenllyeeDataContract
{
????[DataContract]
????public?class?Employee
????{
????????#region?Fields
????????private?string?_name;
????????private?int?_age;
????????#endregion
????????#region?Properties
????????///?<summary>
????????///?The?employee's?name
????????///?</summary>
????????[DataMember(Order=0)]
????????public?string?Name
????????{
????????????get?
????????????{
????????????????return?this._name;
????????????}
????????????set
????????????{
????????????????this._name?=?value;
????????????}
????????}
????????///?<summary>
????????///?The?employee's?age
????????///?</summary>
????????[DataMember(Order=1)]
????????public?int?Age
????????{
????????????get
????????????{
????????????????return?this._age;
????????????}
????????????set
????????????{
????????????????this._age?=?value;
????????????}
????????}
????????#endregion
????}
????[DataContract]
????public?class?Intern?:?Employee
????{
????????private?int?_internship;
????????///?<summary>
????????///?The?intern's?working?days
????????///?</summary>
????????[DataMember]
????????public?int?Internship
????????{
????????????get
????????????{
????????????????return?this._internship;
????????????}
????????????set
????????????{
????????????????this._internship?=?value;
????????????}
????????}
????}
}
?
在數據契約中我們并沒有去指定KnownType,我們在服務契約的操作上去標識ServiceKnownType特性,EmployeeManage.cs:
?
?
Codeusing?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
using?System.ServiceModel;
using?System.Runtime.Serialization;
namespace?HenllyeeServiceContract
{
????[ServiceContract]
????public?interface?IEmployeeManage
????{
????????[OperationContract]
????????[ServiceKnownType(typeof(HenllyeeDataContract.Intern))]
????????void?AddEmployee(HenllyeeDataContract.Employee?emlpoyee);
????????[OperationContract]
????????[ServiceKnownType(typeof(HenllyeeDataContract.Intern))]
????????HenllyeeDataContract.Employee?GetEmployee();
????}
????[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
????public?class?EmployeeManage?:?IEmployeeManage
????{
????????private?HenllyeeDataContract.Employee?_employee;
????????///?<summary>
????????///?Set?employee
????????///?</summary>
????????///?<param?name="emlpoyee">the?employee's?object</param>
????????public?void?AddEmployee(HenllyeeDataContract.Employee?emlpoyee)
????????{
????????????this._employee?=?emlpoyee;
????????}
????????///?<summary>
????????///?Get?a?employee
????????///?</summary>
????????///?<returns></returns>
????????public?HenllyeeDataContract.Employee?GetEmployee()
????????{
????????????return?this._employee;
????????}
????}
}
?
在客戶端我們調用:
?
?
Codeusing?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
namespace?Client
{
????class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????EmployeeService.EmployeeManageClient?proxy?=?new?Client.EmployeeService.EmployeeManageClient();
????????????EmployeeService.Intern?intern?=?new?Client.EmployeeService.Intern();
????????????intern.Age?=?22;
????????????intern.Name?=?"Henllyee?Cui";
????????????intern.Internship?=?120;
????????????proxy.AddEmployee(intern);
????????????EmployeeService.Employee?internOut?=?proxy.GetEmployee();
????????????Console.Write("The?Employee?Name:{0}\nAge:{1}\n",
????????????????internOut.Name,
????????????????internOut.Age
????????????????);
????????????Console.Read();
????????}
????}
}
運行后:?
?????ServiceKnownType特性也可以表示在數據契約的類上,那么就會應用到整個數據契約中操作上,如:
??????????[ServiceContract]
??????????[ServiceDataContract(typeof(HenllyeeDataContract.Intern))]
??????????public?interface?IEmployeeManage{...}
?????那么IEmployeeManage服務契約跟其所有的操作都可以接受Intern這個子類.
已知類型與接口
?????數據契約DataContract只能標識在class 或者struct上,但是數據契約的基類可以是接口,但是我們在服務契約的時候要去用ServiceKnownType特性去指定確切的數據類型。如:
?????interface IEmployee{...}
?????[DataContract]
?????class Intern:IEmployee{...}
服務契約中:
?????[ServiceContract]
?????[ServiceKnownType(typeof(Intern))]
?????interface IEmployeeManage
?????{
??????????[OperationContract]
??????????void AdddEmployee(IEmployee employee);
?????}
要注意的一點就是我們不能把KnownType特性應用到基接口上,因為客服端導出的元數據是不能包含接口本身的。
[代碼下載]
作者:Henllyee Cui出處: http://henllyee.cnblogs.com/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明。
轉載于:https://www.cnblogs.com/Henllyee/archive/2008/08/26/1276995.html
總結
以上是生活随笔為你收集整理的WCF学习(五)数据契约之已知类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于弹框
- 下一篇: 试管婴儿是夫妻双方的吗?