WCF中幾個容易忽略的知識點


近來看WCF相關資料 發現之前一些沒太關注或者有些錯誤認識的知識點,有些也貌似不怎么常用。於是整理了這一則筆記。

1、 WCF中的綁定。

可以通過綁定無參數構造函數實例化綁定,然后調用CreateBindingElements獲取到此種綁定的綁定元素。

WSHttpBinding httpBinding =  new WSHttpBinding(); 

BindingElementCollection collection = httpBinding.CreateBindingElements();
foreach (var element in collection)
{                      

Console.WriteLine(element.GetType().FullName);
}

 
輸入如下: 

 

如果對WSHttpBinding 更換一下構造函數 ,如:

httpBinding = new WSHttpBinding(SecurityMode.Transport); 

輸出結果如下:

 

如果對綁定指定一些配置,如安全配置,則它的綁定元素可能與調用無參數構造函數實例化對象調用CreateBindingElements獲取到的綁定元素不同。也就是說對於同一綁定,使用不同的配置可以更改它的綁定元素類型;不管采用何種配置,對綁定來說傳輸綁定與編碼綁定元素這兩個是必須的。

2、終結點契約配置

配置中的契約contracts不是契約接口的完全限定名,而是ServiceContractAttribute中ConfigurationName指定的名稱。如果沒有ConfigurationName配置,那么contracts的完全限定名與ConfigurationName指定的名稱相同。

3、 UnHandler處理器

如果在WCF中需要一個能處理所有消息的方法,而不關心SOAP消息的Action。那么操作方法

的參數可以指定為Message。這種服務操作在WCF中被稱為UnHandler處理器。這種情況下,參數應為Message;

返回值為void或者Message;OperationCOntractAtrribte的Action設置為"*"


4、WCF序列化中Dos攻擊 

WCF使用的序列化器DataContractSerializer在對數據契約進行序列化或者反序列化時,為了

防止Dos攻擊,在DataContractSerializer中使用MaxItemsInObjectGraph設置了每次序列化得對

象數量。實際使用的時候可以在實現服務契約接口的服務加上ServiceBehavior標簽中進行設置。如:[ServiceBehavior(MaxItemsInObjectGraph = 60)];或者在serviceBehavior的配置中由

dataContractSerializer指定。如:

 

<behavior name= " serviceBehavior ">                

<dataContractSerializer maxItemsInObjectGraph="1000"/>                    
</behavior>

 

5、泛型數據契約問題。

泛型為OO里的一種概念,而服務是基於SOA的,它沒有重載等概念。WCF的默認序列化器DataContractSerializer對

泛型數據契約的序列化,生成的XML默認的根節點元素名稱為:類型名+泛型名1+泛型名2+...+哈希碼。

可以通過指定模板的形式指定DataContractSerializer序列化后的根節點名:{0}{1}...{n}{#}。當然如果能保證數據契約名稱不重復,也可以直接在DataContract中通過Name指定。

6、自定義集合數據契約類型。

自定義集合數據契約:定義類,實現集合接口。如下定義:

     public  class TeacherCollection : IEnumerable<Teacher> 

    {
        private readonly IList<Teacher> teachers = new List<Teacher>();

        public TeacherCollection()
        {
        }



        public TeacherCollection(IList<Teacher> _teachers)
        {
            teachers = _teachers;
        }

        public void Add(Teacher teacher)
        {
            teachers.Add(teacher);
        }


        #region IEnumerable<Teacher> 成員

        public IEnumerator<Teacher> GetEnumerator()
        {
            return teachers.GetEnumerator();
        }

        #endregion

        #region IEnumerable 成員

        IEnumerator IEnumerable.GetEnumerator()
        {
            return teachers.GetEnumerator();
        }

        #endregion
    }

 

在定義契約接口時,可以用自定義集合數據契約。它和IList<Teacher>的區別是:IList<Teacher>中Teacher才是數據契約,IList<Teacher>是數據契約的集合,而TeacherCollection是將整個集合對象最為數據契約。在WCF的默認的序列化器對TeacherCollection和IList<Teacher>的序列化的結果是相同的。

自定義集合契約,如果實現IList接口,則可以不需要添加Add,如果實現了IEmurable接口,則需要Add方法,並且需要有無參構造函數。為了簡化Add方法與構造函數可以讓自定義集合契約直接實現List<T>。
對於自定義集合契約,WCF可以直接使用CollectionDataContract將其標記,泛型類T無需標記為DataContract。如下:
    [CollectionDataContract(Name =  " TeacherList ", ItemName =  " TeacherEntry ", Namespace =  " cnblogs.com ")]
     public  class Collection<T> : List<T>
    {
         private  readonly IList<Teacher> teachers =  new List<Teacher>();
    
    }
 

7、數據契約代理。

數據契約代理實現了IDataContractSurrogate。在WCF中,它可被用於WCF默認的序列器

DataContractSerializer中,用於將數據契約類與其他相似類型的轉化。以下實現Contract類型與

數據契約Employee之間的轉化。

 示例代碼如下:
Contract類:
     public  class Contract
    {
         public  string FullName {  getset; }

         public  string Sex {  getset; }
    }
數據契約Employee:

 

    [DataContract]
     public  class Employee
    {
        [DataMember]
         public  string FirstName {  getset; }

        [DataMember]
         public  string LastName {  getset; }

        [DataMember]
         public  string Gender {  getset; }
    }
實現IDataContractSurrogate接口:

 

    class ContactSurrogate : IDataContractSurrogate
    {

         #region IDataContractSurrogate 成員

         public  object GetCustomDataToExport(Type clrType, Type dataContractType)
        {
             return  null;
        }

         public  object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
        {
             return  null;
        }

         public Type GetDataContractType(Type type)
        {
             if (type== typeof(Contract))
            {
                 return  typeof (Employee);
            }
             return type;
        }

         public  object GetDeserializedObject( object obj, Type targetType)
        {
            Employee employee = obj  as Employee;
             if (employee== null)
            {
                 return obj;
            }
             return  new Contract {FullName = employee.FirstName + employee.LastName, Sex = employee.Gender};
        }

         public  void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)
        {
            
        }

         public  object GetObjectToSerialize( object obj, Type targetType)
        {
            Contract contract = obj  as Contract;
             if (contract ==  null)
            {
                 return obj;
            }
             return  new Employee
                       {
                           FirstName = contract.FullName.Split( "   ".ToArray(), StringSplitOptions.None)[ 0],
                           Gender = contract.Sex,
                           LastName = contract.FullName.Split( "   ".ToArray(), StringSplitOptions.None)[ 1]
                       };
        }

         public Type GetReferencedTypeOnImport( string typeName,  string typeNamespace,  object customData)
        {
             return  null;
        }

         public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
        {
             return typeDeclaration;
        }

         #endregion
    }

 使用ContactSurrogate進行序列化與反序列化的方法:

 

     public  static  void Serializer<T>(T instance, string fileName,IDataContractSurrogate dataContractSurrogate)
        {
            DataContractSerializer serializer= new DataContractSerializer( typeof(T), null,Int32.MaxValue, false, false,dataContractSurrogate);
             using(XmlWriter xmlWriter=XmlWriter.Create(fileName))
            {
                serializer.WriteObject(xmlWriter, instance);
            }
            Process.Start(fileName);
        }

             public  static T DeSerializer<T>( string fileName,IDataContractSurrogate dataContractSurrogate)
        {
            DataContractSerializer serializer =  new DataContractSerializer( typeof(T),  new List<Type>(), Int32.MaxValue,  falsefalse, dataContractSurrogate);
             using (XmlReader xmlReader=XmlReader.Create(fileName))
            {
                 object obj = serializer.ReadObject(xmlReader);
                 return (T) obj;
            }

        }  


現在對數據契約Employee使用Serializer<T>進行序列化,然后將它序列化后的文件使用

DeSerializer<T>將它反序列化成反序列化為Contract對象。

Employee employee =  new Employee {FirstName =  " yongbo ", Gender =  " male ", LastName =  " Tao "};            

ContactSurrogate contactSurrogate = new ContactSurrogate();
        Tools.Serializer(employee, @"C:\DataContractSurrogate.txt", contactSurrogate);

        Contract obj = Tools.DeSerializer<Contract>(@"C:\DataContractSurrogate.txt", contactSurrogate);
        Console.WriteLine(string.Format("{0} 類型為:{1}。FullName is {2},Sex is {3}",obj,obj.GetType().FullName,obj.FullName,obj.Sex));

輸出如下:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM