程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF學習(五):數據契約之已知類型

WCF學習(五):數據契約之已知類型

編輯:關於.NET

准備技術:

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:

using 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:

using 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;
}
}
}

在客戶端我們調用:

using 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特性應用到基接口上,因為客服端導出的元數據是不能包含接口本身的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved