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:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
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:

 

 

ContractedBlock.gif ExpandedBlockStart.gif Code
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;
        }
    }
}

 

在客户端我们调用:

 

 

ContractedBlock.gif ExpandedBlockStart.gif Code
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特性应用到基接口上,因为客服端导出的元数据是不能包含接口本身的。

[代码下载]

作者:Henllyee Cui
出处: http://henllyee.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。

转载于:https://www.cnblogs.com/Henllyee/archive/2008/08/26/1276995.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值