WCF中几个容易忽略的知识点

近来看WCF相关资料 发现以前一些没太关注或者有些错误认识的知识点,有些也貌似不怎么经常使用。因而整理了这一则笔记。

一、 WCF中的绑定。安全

能够经过绑定无参数构造函数实例化绑定,而后调用CreateBindingElements获取到此种绑定的绑定元素。函数

WSHttpBinding httpBinding =  new WSHttpBinding(); 

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

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

 
输入以下: spa

 

若是对WSHttpBinding 更换一下构造函数 ,如:代理

httpBinding = new WSHttpBinding(SecurityMode.Transport); code

输出结果以下:orm

 

若是对绑定指定一些配置,如安全配置,则它的绑定元素可能与调用无参数构造函数实例化对象调用CreateBindingElements获取到的绑定元素不一样。也就是说对于同一绑定,使用不一样的配置能够更改它的绑定元素类型;无论采用何种配置,对绑定来讲传输绑定与编码绑定元素这两个是必须的。

二、终结点契约配置xml

配置中的契约contracts不是契约接口的彻底限定名,而是ServiceContractAttribute中ConfigurationName指定的名称。若是没有ConfigurationName配置,那么contracts的彻底限定名与ConfigurationName指定的名称相同。

三、 UnHandler处理器对象

若是在WCF中须要一个能处理全部消息的方法,而不关心SOAP消息的Action。那么操做方法

的参数能够指定为Message。这种服务操做在WCF中被称为UnHandler处理器。这种状况下,参数应为Message;

返回值为void或者Message;OperationCOntractAtrribte的Action设置为"*"


四、WCF序列化中Dos攻击 

WCF使用的序列化器DataContractSerializer在对数据契约进行序列化或者反序列化时,为了

防止Dos攻击,在DataContractSerializer中使用MaxItemsInObjectGraph设置了每次序列化得对

象数量。实际使用的时候能够在实现服务契约接口的服务加上ServiceBehavior标签中进行设置。如:[ServiceBehavior(MaxItemsInObjectGraph = 60)];或者在serviceBehavior的配置中由

dataContractSerializer指定。如:

 

<behavior name= " serviceBehavior ">                

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

 

五、泛型数据契约问题。

泛型为OO里的一种概念,而服务是基于SOA的,它没有重载等概念。WCF的默认序列化器DataContractSerializer对

泛型数据契约的序列化,生成的XML默认的根节点元素名称为:类型名+泛型名1+泛型名2+...+哈希码。

能够经过指定模板的形式指定DataContractSerializer序列化后的根节点名:{0}{1}...{n}{#}。固然若是能保证数据契约名称不重复,也能够直接在DataContract中经过Name指定。

六、自定义集合数据契约类型。

自定义集合数据契约:定义类,实现集合接口。以下定义:

     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>();
    
    }
 

七、数据契约代理。

数据契约代理实现了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));

输出以下: