ITPub博客

首页 > Linux操作系统 > Linux操作系统 > WCF学习(五):数据契约之已知类型

WCF学习(五):数据契约之已知类型

原创 Linux操作系统 作者:iDotNetSpace 时间:2009-05-18 17:30:31 0 删除 编辑

准备技术:

     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:

 

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
        ///


        /// The employee's name
        ///

        [DataMember(Order=0)]
        public string Name
        {
            get
            {
                return this._name;
            }
            set
            {
                this._name = value;
            }
        }

        ///


        /// The employee's age
        ///

        [DataMember(Order=1)]
        public int Age
        {
            get
            {
                return this._age;
            }
            set
            {
                this._age = value;
            }
        }
        #endregion
    }

    [DataContract]
    public class Intern : Employee
    {
        private int _internship;

        ///


        /// The intern's working days
        ///

        [DataMember]
        public int Internship
        {
            get
            {
                return this._internship;
            }
            set
            {
                this._internship = value;
            }
        }
    }
}

 

在数据契约中我们并没有去指定KnownType,我们在服务契约的操作上去标识ServiceKnownType特性,EmployeeManage.cs:

 

 

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;

        ///


        /// Set employee
        ///

        /// the employee's object
        public void AddEmployee(HenllyeeDataContract.Employee emlpoyee)
        {
            this._employee = emlpoyee;
        }

        ///


        /// Get a employee
        ///

        ///
        public HenllyeeDataContract.Employee GetEmployee()
        {
            return this._employee;
        }
    }
}

 

在客户端我们调用:

 

 

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

原文:http://www.cnblogs.com/Henllyee/archive/2008/08/26/1276995.html

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12639172/viewspace-600252/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2008-01-04

  • 博文量
    2376
  • 访问量
    5322126