WCF开发之自定义序列化(IXmlSerializable)

这部分东西需要XML相关知识和序列化和反序列化的知识,下面我们根据一个Demo来理解一下自定义序列化的过程。

这个例子的程序结构和之前的都是一样的,唯一不同的我们这里没有使用DataContract,而是采用自己来编写序列化器的方法,为什么要自定义哪?

在完美的WCF世界中:
– 创建同业务对象描述相同功能的数据契约
– 暴露在服务契约中
在现实世界中:
– 可能无法拥有对象(不可序列化)
– 业务对象的实例化可能不正确
– 可能需要对现存的schema进行支持

如何自定义序列化气?他是怎样实现的那?

IXmlSerializable 类型为WSDL和元数据交换(MEX)提供了XSD schema
– 支持Contract-first
开发人员自己处理XML与业务对象之间的映射关系
– 需要具备XML的相关知识
– 进行适当的交验
• 在开销上较使用临时的数据契约少

IXmlSerializable
– 在服务契约中验证(类似数据契约)
在序列化过程中执行:
– IXmlSerializable.ReadXml()
– IXmlSerializable.WriteXml()
XmlSchemaProviderAttribute
– 改进IXmlSerializable.GetSchema()
– 为WSDL和MEX返回schema

看具体代码:

ExpandedBlockStart.gif LinkItem代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Runtime.Serialization;

namespace  ContentTypes
{
    
public   class  LinkItem
    {
        
private   long  m_id;
        
private   string  m_title;
        
private   string  m_description;
        
private  DateTime m_dateStart;
        
private  DateTime m_dateEnd;
        
private   string  m_url;

        
public   long  Id
        {
            
get  {  return  m_id; }
            
set  { m_id  =  value; }
        }

        
public   string  Title
        {
            
get  {  return  m_title; }
            
set  { m_title  =  value; }
        }

        
public   string  Description
        {
            
get  {  return  m_description; }
            
set  { m_description  =  value; }
        }

        
public  DateTime DateStart
        {
            
get  {  return  m_dateStart; }
            
set  { m_dateStart  =  value; }
        }

        
public  DateTime DateEnd
        {
            
get  {  return  m_dateEnd; }
            
set  { m_dateEnd  =  value; }
        }

        
public   string  Url
        {
            
get  {  return  m_url; }
            
set  { m_url  =  value; }
        }
    }
}

 

上面的LinkItem没有使用DataContract和DataMember所以他目前只是一个普通的类,WCF不会为他自动创建序列化器,所以他不能再Server和Client之间直接进行传递。

下面开Service端的代码,这个文件就是我们自己定义的LinkItem的序列化器:

ExpandedBlockStart.gif LinkItemSerializer 代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Xml.Serialization;
using  ContentTypes;
using  System.Xml;
using  System.Xml.Schema;
using  System.IO;

namespace  WcfServiceLibraryDemo
{
    [XmlSchemaProvider(
" GetSchema " )]
    
public   class  LinkItemSerializer : IXmlSerializable
    {
        
static   string  ns  =   " http://www.cnblogs.com/Charlesliu " ;
        
static   string  xs  =   " http://www.w3.org/2001/XMLSchema " ;

        
private  LinkItem m_linkItem;

        
public  LinkItem LinkItem
        {
            
get  {  return  m_linkItem; }
            
set  { m_linkItem  =  value; }
        }

        
public  LinkItemSerializer()
        {
        }

        
public  LinkItemSerializer(LinkItem item)
        {
            
this .m_linkItem  =  item;
        }

        
public   static  XmlQualifiedName GetSchema(XmlSchemaSet schemaSet)
        {

            
string  schemaString  =  String.Format(
                
" <xs:schema xmlns:tns='{0}' xmlns:xs='{1}' targetNamespace='{0}' elementFormDefault='qualified' attributeFormDefault='unqualified'> "   +
                
" <xs:complexType name='LinkItem'> "   +
                
" <xs:sequence> "   +
                
" <xs:element name='Id' type='xs:long' nillable='false'/> "   +
                
" <xs:element name='Title' type='xs:string' nillable='false'/> "   +
                
" <xs:element name='Description' type='xs:string' nillable='false'/> "   +
                
" <xs:element name='DateStart' type='xs:dateTime' nillable='false'/> "   +
                
" <xs:element name='DateEnd' type='xs:dateTime' nillable='true' minOccurs='0'/> "   +
                
" <xs:element name='Url' type='xs:string' nillable='false' minOccurs='0'/> "   +
                
" </xs:sequence> "   +
                
" </xs:complexType> "   +
                
" </xs:schema> " , ns, xs);

            XmlSchema schema 
=  XmlSchema.Read( new  StringReader(schemaString),  null );
            schemaSet.XmlResolver 
=   new  XmlUrlResolver();
            schemaSet.Add(schema);

            
return   new  XmlQualifiedName( " LinkItem " , ns);
        }

        System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
        {
            
throw   new  NotImplementedException( " IXmlSerializable.GetSchema() is not implemented. Use static GetSchema() instead. " );
        }

        
void  IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
        {

            LinkItem item 
=   new  LinkItem();

            
while  (reader.IsStartElement())
            {
                reader.MoveToContent();
                reader.Read();

                
if  (reader.IsStartElement( " Id " ))
                {
                    reader.MoveToContent();
                    item.Id 
=   int .Parse(reader.ReadString());
                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                
else
                    
throw   new  XmlException( " ExpectedElementMissing: Id element was expected. " );

                
if  (reader.IsStartElement( " Title " ))
                {
                    reader.MoveToContent();
                    item.Title 
=  reader.ReadString();
                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                
else
                    
throw   new  XmlException( " ExpectedElementMissing: Title element was expected. " );

                
if  (reader.IsStartElement( " Description " ))
                {
                    reader.MoveToContent();
                    item.Description 
=  reader.ReadString();
                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                
else
                    
throw   new  XmlException( " ExpectedElementMissing: Description element was expected. " );

                
if  (reader.IsStartElement( " DateStart " ))
                {
                    reader.MoveToContent();
                    reader.Read();
                    item.DateStart 
=  reader.ReadContentAsDateTime();
                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                
else
                    
throw   new  XmlException( " ExpectedElementMissing: DateStart element was expected. " );

                
if  (reader.IsStartElement( " DateEnd " ))
                {
                    reader.MoveToContent();
                    reader.Read();
                    item.DateEnd 
=  reader.ReadContentAsDateTime();
                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                
//  optional

                
if  (reader.IsStartElement( " Url " ))
                {
                    reader.MoveToContent();
                    item.Url 
=  reader.ReadString();

                    reader.MoveToContent();
                    reader.ReadEndElement();
                }
                
else
                    
throw   new  XmlException( " ExpectedElementMissing: Url element was expected. " );

                reader.MoveToContent();
                reader.ReadEndElement();
            }


            
this .m_linkItem  =  item;
        }

        
void  IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
        {

            writer.WriteStartElement(
" Id " , ns);
            writer.WriteValue(m_linkItem.Id);
            writer.WriteEndElement();

            writer.WriteElementString(
" Title " , ns, m_linkItem.Title);
            writer.WriteElementString(
" Description " , ns, m_linkItem.Description);

            writer.WriteStartElement(
" DateStart " , ns);
            writer.WriteValue(m_linkItem.DateStart);
            writer.WriteEndElement();

            writer.WriteStartElement(
" DateEnd " , ns);
            writer.WriteValue(m_linkItem.DateEnd);
            writer.WriteEndElement();

            writer.WriteElementString(
" Url " , ns, m_linkItem.Url);

        }
    }
}

 

下面详细讲解这段代码,首先对于自定义的序列化器一定要实现System.Xml.Serialization.IXmlSerializable接口,[XmlSchemaProvider("GetSchema")]用途是标示出提供Schema的对应方法名字,也就是说应该有一个GetSchema的方法与之对应。程序中通常要把LinkItem这个待序列化的Class定义为属性在序列化其中,以方便访问。对于IXmlSerializable这个接口,要实现下面3个方法:

XmlSchema GetSchema();

void ReadXml(XmlReader reader);

void WriteXml(XmlWriter writer);

实际应用中通常不处理GetSchema()这个方法,而是定义一个静态的方法GetSchema(XmlSchemaSet schemaSet)和[XmlSchemaProvider("GetSchema")]这个标签对应,上面代码的就是序列化的经典过程,其中GetSchema充当了生产XML结构的左右,Write和Read两个方法实现把对象数据写入xml中(序列化)和把xml中对象数据重新为给某对象(反序列化)。

注意此时,Service代码的参数也要同时改变。

ExpandedBlockStart.gif IGigManagerService代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Runtime.Serialization;
using  System.ServiceModel;
using  System.Text;
using  ContentTypes;

namespace  WcfServiceLibraryDemo
{
    [ServiceContract(Name 
=   " GigManagerServiceContract " , Namespace  =   " http://www.cnblogs.com/Charlesliu " , SessionMode  =  SessionMode.Required)]
    
public   interface  IGigManagerService
    {
        [OperationContract(Name 
=   " SaveGig " , Action  =   " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/SaveGig " , ReplyAction  =   " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/SaveGigResponse " )]
        
void  SaveGig(LinkItemSerializer item);

        [OperationContract(Name 
=   " GetGig " , Action  =   " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/GetGig " , ReplyAction  =   " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/GetGigResponse " )]
        LinkItemSerializer GetGig();
    }
}

 

 

ExpandedBlockStart.gif GigManagerService 代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Runtime.Serialization;
using  System.ServiceModel;
using  System.Text;
using  ContentTypes;

namespace  WcfServiceLibraryDemo
{
    [ServiceBehavior(InstanceContextMode 
=  InstanceContextMode.PerSession)]
    
public   class  GigManagerService : IGigManagerService
    {

        
private  LinkItem m_linkItem;

        
#region  IGigManager Members

        
public   void  SaveGig(LinkItemSerializer item)
        {
            m_linkItem 
=  item.LinkItem;
        }

        
public  LinkItemSerializer GetGig()
        {
            
return   new  LinkItemSerializer(m_linkItem);
        }

        
#endregion
    }
}

客户端的代码不变:

ExpandedBlockStart.gif Form1代码
using  System;
using  System.Collections.Generic;
using  System.ComponentModel;
using  System.Data;
using  System.Drawing;
using  System.Linq;
using  System.Text;
using  System.Windows.Forms;
using  WinTest.MyServiceReference;

namespace  WinTest
{
    
public   partial   class  Form1 : Form
    {
        MyServiceReference.GigManagerServiceContractClient m_proxy 
=   new  WinTest.MyServiceReference.GigManagerServiceContractClient();

        
public  Form1()
        {
            InitializeComponent();
        }

        
private   void  cmdSave_Click( object  sender, EventArgs e)
        {
            LinkItem item 
=   new  LinkItem();

            item.Id 
=   int .Parse( this .txtId.Text);
            item.Title 
=   this .txtTitle.Text;
            item.Description 
=   this .txtDescription.Text;
            item.DateStart 
=   this .dtpStart.Value;
            item.DateEnd 
=   this .dtpEnd.Value;
            item.Url 
=   this .txtUrl.Text;

            m_proxy.SaveGig(item);
        }

        
private   void  cmdGet_Click( object  sender, EventArgs e)
        {
            LinkItem item 
=  m_proxy.GetGig();
            
if  (item  !=   null )
            {
                
this .txtId.Text  =  item.Id.ToString();
                
this .txtTitle.Text  =  item.Title;
                
this .txtDescription.Text  =  item.Description;

                
if  (item.DateStart  !=  DateTime.MinValue)
                    
this .dtpStart.Value  =  item.DateStart;
                
if  (item.DateEnd  !=  DateTime.MinValue)
                    
this .dtpEnd.Value  =  (DateTime)item.DateEnd;

                
this .txtUrl.Text  =  item.Url;
            }
        }
    }
}

 

ExpandedBlockStart.gif Proxy 代码
// ------------------------------------------------------------------------------
//  <auto-generated>
//      This code was generated by a tool.
//      Runtime Version:2.0.50727.4200
//
//      Changes to this file may cause incorrect behavior and will be lost if
//      the code is regenerated.
//  </auto-generated>
// ------------------------------------------------------------------------------

namespace  WinTest.MyServiceReference {
    
using  System.Runtime.Serialization;
    
using  System;
    
    
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute(
" System.Runtime.Serialization " " 3.0.0.0 " )]
    [System.Runtime.Serialization.DataContractAttribute(Name
= " LinkItem " , Namespace = " http://www.cnblogs.com/Charlesliu " )]
    [System.SerializableAttribute()]
    
public   partial   class  LinkItem :  object , System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
        
        [System.NonSerializedAttribute()]
        
private  System.Runtime.Serialization.ExtensionDataObject extensionDataField;
        
        
private   long  IdField;
        
        
private   string  TitleField;
        
        
private   string  DescriptionField;
        
        
private  System.DateTime DateStartField;
        
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        
private  System.Nullable < System.DateTime >  DateEndField;
        
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        
private   string  UrlField;
        
        [
global ::System.ComponentModel.BrowsableAttribute( false )]
        
public  System.Runtime.Serialization.ExtensionDataObject ExtensionData {
            
get  {
                
return   this .extensionDataField;
            }
            
set  {
                
this .extensionDataField  =  value;
            }
        }
        
        [System.Runtime.Serialization.DataMemberAttribute(IsRequired
= true )]
        
public   long  Id {
            
get  {
                
return   this .IdField;
            }
            
set  {
                
if  (( this .IdField.Equals(value)  !=   true )) {
                    
this .IdField  =  value;
                    
this .RaisePropertyChanged( " Id " );
                }
            }
        }
        
        [System.Runtime.Serialization.DataMemberAttribute(IsRequired
= true , EmitDefaultValue = false )]
        
public   string  Title {
            
get  {
                
return   this .TitleField;
            }
            
set  {
                
if  (( object .ReferenceEquals( this .TitleField, value)  !=   true )) {
                    
this .TitleField  =  value;
                    
this .RaisePropertyChanged( " Title " );
                }
            }
        }
        
        [System.Runtime.Serialization.DataMemberAttribute(IsRequired
= true , EmitDefaultValue = false , Order = 2 )]
        
public   string  Description {
            
get  {
                
return   this .DescriptionField;
            }
            
set  {
                
if  (( object .ReferenceEquals( this .DescriptionField, value)  !=   true )) {
                    
this .DescriptionField  =  value;
                    
this .RaisePropertyChanged( " Description " );
                }
            }
        }
        
        [System.Runtime.Serialization.DataMemberAttribute(IsRequired
= true , Order = 3 )]
        
public  System.DateTime DateStart {
            
get  {
                
return   this .DateStartField;
            }
            
set  {
                
if  (( this .DateStartField.Equals(value)  !=   true )) {
                    
this .DateStartField  =  value;
                    
this .RaisePropertyChanged( " DateStart " );
                }
            }
        }
        
        [System.Runtime.Serialization.DataMemberAttribute(Order
= 4 )]
        
public  System.Nullable < System.DateTime >  DateEnd {
            
get  {
                
return   this .DateEndField;
            }
            
set  {
                
if  (( this .DateEndField.Equals(value)  !=   true )) {
                    
this .DateEndField  =  value;
                    
this .RaisePropertyChanged( " DateEnd " );
                }
            }
        }
        
        [System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue
= false , Order = 5 )]
        
public   string  Url {
            
get  {
                
return   this .UrlField;
            }
            
set  {
                
if  (( object .ReferenceEquals( this .UrlField, value)  !=   true )) {
                    
this .UrlField  =  value;
                    
this .RaisePropertyChanged( " Url " );
                }
            }
        }
        
        
public   event  System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        
        
protected   void  RaisePropertyChanged( string  propertyName) {
            System.ComponentModel.PropertyChangedEventHandler propertyChanged 
=   this .PropertyChanged;
            
if  ((propertyChanged  !=   null )) {
                propertyChanged(
this new  System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }
    }
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute(
" System.ServiceModel " " 3.0.0.0 " )]
    [System.ServiceModel.ServiceContractAttribute(Namespace
= " http://www.cnblogs.com/Charlesliu " , ConfigurationName = " MyServiceReference.GigManagerServiceContract " , SessionMode = System.ServiceModel.SessionMode.Required)]
    
public   interface  GigManagerServiceContract {
        
        [System.ServiceModel.OperationContractAttribute(Action
= " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/SaveGig " , ReplyAction = " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/SaveGigResponse " )]
        
void  SaveGig(WinTest.MyServiceReference.LinkItem item);
        
        [System.ServiceModel.OperationContractAttribute(Action
= " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/GetGig " , ReplyAction = " http://www.cnblogs.com/Charlesliu/GigManagerServiceContract/GetGigResponse " )]
        WinTest.MyServiceReference.LinkItem GetGig();
    }
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute(
" System.ServiceModel " " 3.0.0.0 " )]
    
public   interface  GigManagerServiceContractChannel : WinTest.MyServiceReference.GigManagerServiceContract, System.ServiceModel.IClientChannel {
    }
    
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute(
" System.ServiceModel " " 3.0.0.0 " )]
    
public   partial   class  GigManagerServiceContractClient : System.ServiceModel.ClientBase < WinTest.MyServiceReference.GigManagerServiceContract > , WinTest.MyServiceReference.GigManagerServiceContract {
        
        
public  GigManagerServiceContractClient() {
        }
        
        
public  GigManagerServiceContractClient( string  endpointConfigurationName) : 
                
base (endpointConfigurationName) {
        }
        
        
public  GigManagerServiceContractClient( string  endpointConfigurationName,  string  remoteAddress) : 
                
base (endpointConfigurationName, remoteAddress) {
        }
        
        
public  GigManagerServiceContractClient( string  endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
                
base (endpointConfigurationName, remoteAddress) {
        }
        
        
public  GigManagerServiceContractClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                
base (binding, remoteAddress) {
        }
        
        
public   void  SaveGig(WinTest.MyServiceReference.LinkItem item) {
            
base .Channel.SaveGig(item);
        }
        
        
public  WinTest.MyServiceReference.LinkItem GetGig() {
            
return   base .Channel.GetGig();
        }
    }
}

自定义序列化的结果是通过VS工程无法正常的引用WCF服务,所以要用命令svcutil.exe http://localhost:9000/才能得到Proxy文件,将这个文件copy到客户端工程中就可以使用了。同时要把自动生成的配置文件也copy进去。

自定义序列化的给程序员提供了更加灵活的方式,因为现实世界中总是有这样那样的问题,有些时候无法用理想中的WCF的DataContract来完成。当然了,灵活了程序员就费劲了,但是不可否认这种方式的意义所在。(完)自定义序列化的给程序员提供了更加灵活的方式,因为现实世界中总是有这样那样的问题,有些时候无法用理想中的WCF的DataContract来完成。当然了,灵活了程序员就费劲了,但是不可否认这种方式的意义所在。(完)

更正个错误,在Service Class 里的LInkItem应该定义成static。

 

转载于:https://www.cnblogs.com/CharlesLiu/archive/2010/02/08/1663662.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值