现在的位置: 首页 > 综合 > 正文

谈谈WCF中的Data Contract(2):WCF Data Contract对Generic的支持

2011年07月19日 ⁄ 综合 ⁄ 共 6635字 ⁄ 字号 评论关闭
通过第一部分的介绍,我们可以体会到,WCF Data ContractCLR TypeNeutral Contract之间搭建了一座桥梁,弥合了.NET世界和厂商中立世界的差异。通过WCF Data Contract我们将CLR Data Type暴露成一个厂商中立的数据结构的描述,同样通过WCF Data Contract我们将一个现有的CLR Data Type和既定的Neutral contract进行适配。

.NET中,基于Primary Type,比如Int32String等等,他们具有一个简单的默认的序列化方式和结构,可以说他们不需要Data Contract。接下来我们主要讨论的是一些相对比较特殊的、完全基于.NETData Type,比如GenericCollection,和Dictionary。首先,我们结合例子来谈谈基于GenericData TypeData Contract

假设我们需要创建一个用于处理一些单据(Bill)的Service,比如如Order BillSales Bill等。一般的单据都有一个单据头(Header)和明细(Detail)列表,为此我们创建了一个GenericBill。并

namespace Artech.SpecialDataContract.Contract
{
    [DataContract]
    
public class Bill<THeader, TDetail>
    
{
        [DataMember]
        
public THeader Header
        
getset; }

        [DataMember]
        
public IList<TDetail> DetailList
        
getset; }
    }


    [DataContract]
    
public class OrderHeader
    
{
        [DataMember]
        
public Guid OrderID
        
getset; }

        [DataMember]
        
public DateTime OrderDate
        
getset; }
    }


    [DataContract]
    
public class OrderDetail
    
{
        [DataMember]
        
public Guid ProductID
        
getset; }

        [DataMember]
        
public int Quantity
        
getset; }
    }


}

为处理订单单据创建了机遇订单的HeaderDetail

对于一个
Neutral Service ContractNeutral Data Contract本身是不可能支持Generic的,也就是Neutral Contract只能是对一个具体的CLR Type的体现。所以在定义Service Contract的时候,对于那些包含Generic Type作为参数或者返回值得Operation,我们必须指定一个具体的Data Type。所以我们创建了如下一个IBillManager Service Contract

 

namespace Artech.SpecialDataContract.Contract
{
    [ServiceContract]
    
public interface IBillManager
    
{
        [OperationContract]
        
void Procss(Bill<OrderHeader, OrderDetail> orderBill);
    }

}

如何我们现在

Host基于这样一个ContractService,你猜我们作为参数的数据类型将会如何体现的。

 

通过WSDL,我们会发现该ServiceData Contract将会以下面一段XSD的方式来呈现:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Artech.SpecialDataContract.Contract"
    xmlns:xs
="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.datacontract.org/2004/07/Artech.SpecialDataContract.Contract"
    xmlns:ser
="http://schemas.microsoft.com/2003/10/Serialization/">
  
<xs:import schemaLocation="http://artech/Artech.SpecialDataContract/BillManagerService.svc?xsd=xsd1"
      namespace
="http://schemas.microsoft.com/2003/10/Serialization/" />
  
<xs:complexType name="BillOfOrderHeaderOrderDetailLZ9Dq20o">
    
<xs:annotation>
      
<xs:appinfo>
        
<GenericType Name="BillOf{0}{1}{#}" Namespace="http://schemas.datacontract.org/2004/07/Artech.SpecialDataContract.Contract"
            xmlns
="http://schemas.microsoft.com/2003/10/Serialization/">
          
<GenericParameter Name="OrderHeader" Namespace="http://schemas.datacontract.org/2004/07/Artech.SpecialDataContract.Contract"/>
          
<GenericParameter Name="OrderDetail" Namespace="http://schemas.datacontract.org/2004/07/Artech.SpecialDataContract.Contract"/>
        
</GenericType>
      
</xs:appinfo>
    
</xs:annotation>
    
<xs:sequence>
      
<xs:element minOccurs="0" name="DetailList" nillable="true" type="tns:ArrayOfOrderDetail"/>
      
<xs:element minOccurs="0" name="Header" nillable="true" type="tns:OrderHeader"/>
    
</xs:sequence>
  
</xs:complexType>
  
<xs:element name="BillOfOrderHeaderOrderDetailLZ9Dq20o" nillable="true" type="tns:BillOfOrderHeaderOrderDetailLZ9Dq20o"/>
  
<xs:complexType name="ArrayOfOrderDetail">
    
<xs:sequence>
      
<xs:element minOccurs="0" maxOccurs="unbounded" name="OrderDetail" nillable="true" type="tns:OrderDetail"/>
    
</xs:sequence>
  
</xs:complexType>
  
<xs:element name="ArrayOfOrderDetail" nillable="true" type="tns:ArrayOfOrderDetail"/>
  
<xs:complexType name="OrderDetail">
    
<xs:sequence>
      
<xs:element minOccurs="0" name="ProductID" type="ser:guid"/>
      
<xs:element minOccurs="0" name="Quantity" type="xs:int"/>
    
</xs:sequence>
  
</xs:complexType>
  
<xs:element name="OrderDetail" nillable="true" type="tns:OrderDetail"/>
  
<xs:complexType name="OrderHeader">
    
<xs:sequence>
      
<xs:element minOccurs="0" name="OrderDate" type="xs:dateTime"/>
      
<xs:element minOccurs="0" name="OrderID" type="ser:guid"/>
    
</xs:sequence>
  
</xs:complexType>
  
<xs:element name="OrderHeader" nillable="true" type="tns:OrderHeader"/>
</xs:schema>

对于不习惯看XSD的朋友,我们可以通过Add Service Reference的方式创建本地的Proxy file,借助生成的与之对应的Class来看看这个XSD最终呈现的结构:

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute(
"System.Runtime.Serialization""3.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name
="BillOfOrderHeaderOrderDetailLZ9Dq20o", Namespace="http://schemas.datacontract.org/2004/07/Artech.SpecialDataContract.Contract")]
    [System.SerializableAttribute()]
    
public partial class BillOfOrderHeaderOrderDetailLZ9Dq20o : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
        
        [System.NonSerializedAttribute()]
        
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
        
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        
private Artech.SpecialDataContract.Client.BillManagerService.OrderDetail[] DetailListField;
        
        [System.Runtime.Serialization.OptionalFieldAttribute()]
        
private Artech.SpecialDataContract.Client.BillManagerService.OrderHeader HeaderField;
        
        [global::System.ComponentModel.BrowsableAttribute(
false)]
        
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
            
get {
                
return this.extensionDataField;
            }

            
set {
                
this.extensionDataField = value;
            }

        }

        
        [System.Runtime.Serialization.DataMemberAttribute()]
        
public Artech.SpecialDataContract.Client.BillManagerService.OrderDetail[] DetailList {
            
get {
                
return this.DetailListField;
            }

            
set {
                
if ((object.ReferenceEquals(this.DetailListField, value) != true)) {
                    
this.DetailListField = value;
                    
this.RaisePropertyChanged("DetailList");
                }

            }

        }

        
        [System.Runtime.Serialization.DataMemberAttribute()]
        
public Artech.SpecialDataContract.Client.BillManagerService.OrderHeader Header {
            
get {
                
return this.HeaderField;
            }

            
set {
                
if ((object.ReferenceEquals(this.HeaderField, value) != true)) {
                    
this.HeaderField = value;
                    
this.RaisePropertyChanged("Header");
                }

            }

        }

        
        
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        

抱歉!评论已关闭.