WCF中幾個容易忽略的知識點
近來看WCF相關(guān)資料 發(fā)現(xiàn)之前一些沒太關(guān)注或者有些錯誤認識的知識點,有些也貌似不怎么常用。于是整理了這一則筆記。
1、 WCF中的綁定。
可以通過綁定無參數(shù)構(gòu)造函數(shù)實例化綁定,然后調(diào)用CreateBindingElements獲取到此種綁定的綁定元素。
- WSHttpBinding httpBinding = new WSHttpBinding();
- BindingElementCollection collection = httpBinding.CreateBindingElements();
- foreach (var element in collection)
- {
- Console.WriteLine(element.GetType().FullName);
- }
輸入如下:

如果對WSHttpBinding 更換一下構(gòu)造函數(shù) ,如:
- httpBinding = new WSHttpBinding(SecurityMode.Transport);
輸出結(jié)果如下:
如果對綁定指定一些配置,如安全配置,則它的綁定元素可能與調(diào)用無參數(shù)構(gòu)造函數(shù)實例化對象調(diào)用CreateBindingElements獲取到的綁定元素不同。也就是說對于同一綁定,使用不同的配置可以更改它的綁定元素類型;不管采用何種配置,對綁定來說傳輸綁定與編碼綁定元素這兩個是必須的。
2、終結(jié)點契約配置
配置中的契約contracts不是契約接口的完全限定名,而是ServiceContractAttribute中ConfigurationName指定的名稱。如果沒有ConfigurationName配置,那么contracts的完全限定名與ConfigurationName指定的名稱相同。
3、 UnHandler處理器
如果在WCF中需要一個能處理所有消息的方法,而不關(guān)心SOAP消息的Action。那么操作方法的參數(shù)可以指定為Message。這種服務操作在WCF中被稱為UnHandler處理器。這種情況下,參數(shù)應為Message;返回值為void或者Meaage;
OperationCOntractAtrribte的Action設置為"*"
4、WCF序列化中Dos攻擊
DataContractSerializer中使用MaxItemsInObjectGraph設置了每次序列化得對象數(shù)量。實際使用的時候可以在實現(xiàn)服務
契約接口的服務加上ServiceBehavior標簽中進行設置。如[ServiceBehavior(MaxItemsInObjectGraph = 60)];或者在serviceBehavior的配置中由dataContractSerializer指定。如
- <behavior name="serviceBehavior">
- <dataContractSerializer maxItemsInObjectGraph="1000"/>
- </behavior>
5、泛型數(shù)據(jù)契約問題。
泛型為OO里的一種概念,而服務是基于SOA的,它沒有重載等概念。WCF的默認序列化器DataContractSerializer對
泛型數(shù)據(jù)契約的序列化,生成的XML默認的根節(jié)點元素名稱為:類型名+泛型名1+泛型名2+...+哈希碼。
可以通過指定模板的形式指定DataContractSerializer序列化后的根節(jié)點名:{0}{1}...{n}{#}。當然如果能保證數(shù)據(jù)契約名稱不重復,也可以直接在DataContract中通過Name指定。
6、自定義集合數(shù)據(jù)契約類型。
自定義集合數(shù)據(jù)契約:定義類,實現(xiàn)集合接口。如下定義:
- 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
- }
在定義契約接口時,可以用自定義集合數(shù)據(jù)契約。它和IList<Teacher>的區(qū)別是:IList<Teacher>中Teacher才是數(shù)據(jù)契約,IList<Teacher>是數(shù)據(jù)契約的集合,而TeacherCollection是將整個集合對象最為數(shù)據(jù)契約。在WCF的默認的序列化器對TeacherCollection和IList<Teacher>的序列化的結(jié)果是相同的。
自定義集合契約,如果實現(xiàn)IList接口,則可以不需要添加Add,如果實現(xiàn)了IEmurable接口,則需要Add方法,并且需要有無參構(gòu)造函數(shù)。為了簡化Add方法與構(gòu)造函數(shù)可以讓自定義集合契約直接實現(xiàn)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、數(shù)據(jù)契約代理。
數(shù)據(jù)契約代理實現(xiàn)了IDataContractSurrogate。在WCF中,它可被用于WCF默認的序列器
DataContractSerializer中,用于將數(shù)據(jù)契約類與其他相似類型的轉(zhuǎn)化。以下實現(xiàn)Contract類型與數(shù)據(jù)契約Employee之間
的轉(zhuǎn)化。
示例代碼如下:
Contract類:
- public class Contract
- {
- public string FullName { get; set; }
- public string Sex { get; set; }
- }
數(shù)據(jù)契約Employee:
- [DataContract]
- public class Employee
- {
- [DataMember]
- public string FirstName { get; set; }
- [DataMember]
- public string LastName { get; set; }
- [DataMember]
- public string Gender { get; set; }
- }
實現(xiàn)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, false, false, dataContractSurrogate);
- using (XmlReader xmlReader=XmlReader.Create(fileName))
- {
- object obj = serializer.ReadObject(xmlReader);
- return (T) obj;
- }
- }
現(xiàn)在對數(shù)據(jù)契約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));
輸出如下:


2012-05-08 09:10:56




