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

开发 后端
我们今天将谈到WCF中的绑定、终结点契约配置、UnHandler处理器、WCF序列化中Dos攻击、自定义集合数据契约类型等知识点。

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

1、 WCF中的绑定

可以通过绑定无参数构造函数实例化绑定,然后调用CreateBindingElements获取到此种绑定的绑定元素。

  1. WSHttpBinding httpBinding = new WSHttpBinding();  
  2. BindingElementCollection collection = httpBinding.CreateBindingElements();  
  3. foreach (var element in collection)  
  4. {  
  5. Console.WriteLine(element.GetType().FullName);  

输入如下:

如果对WSHttpBinding 更换一下构造函数 ,如:

  1. httpBinding = new WSHttpBinding(SecurityMode.Transport); 

输出结果如下:

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

2、终结点契约配置

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

3、 UnHandler处理器

如果在WCF中需要一个能处理所有消息的方法,而不关心SOAP消息的Action。那么操作方法的参数可以指定为Message。这种服务操作在WCF中被称为UnHandler处理器。这种情况下,参数应为Message;返回值为void或者Meaage;

OperationCOntractAtrribte的Action设置为"*"

4、WCF序列化中Dos攻击

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

DataContractSerializer中使用MaxItemsInObjectGraph设置了每次序列化得对象数量。实际使用的时候可以在实现服务

契约接口的服务加上ServiceBehavior标签中进行设置。如[ServiceBehavior(MaxItemsInObjectGraph = 60)];或者在serviceBehavior的配置中由dataContractSerializer指定。如

  1. <behavior name="serviceBehavior"> 
  2. <dataContractSerializer maxItemsInObjectGraph="1000"/>   
  3. </behavior> 

5、泛型数据契约问题。

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

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

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

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

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

  1. public class TeacherCollection : IEnumerable<Teacher>  
  2. {  
  3. private readonly IList<Teacher> teachers = new List<Teacher>();  
  4. public TeacherCollection()  
  5. {  
  6. }  
  7. public TeacherCollection(IList<Teacher> _teachers)  
  8. {  
  9. teachers = _teachers;  
  10. }  
  11. public void Add(Teacher teacher)  
  12. {  
  13. teachers.Add(teacher);  
  14. }  
  15. #region IEnumerable<Teacher> 成员  
  16. public IEnumerator<Teacher> GetEnumerator()  
  17. {  
  18. return teachers.GetEnumerator();  
  19. }  
  20. #endregion  
  21. #region IEnumerable 成员  
  22. IEnumerator IEnumerable.GetEnumerator()  
  23. {  
  24. return teachers.GetEnumerator();  
  25. }  
  26. #endregion  

在定义契约接口时,可以用自定义集合数据契约。它和IList<Teacher>的区别是:IList<Teacher>中Teacher才是数据契约,IList<Teacher>是数据契约的集合,而TeacherCollection是将整个集合对象最为数据契约。在WCF的默认的序列化器对TeacherCollection和IList<Teacher>的序列化的结果是相同的。

自定义集合契约,如果实现IList接口,则可以不需要添加Add,如果实现了IEmurable接口,则需要Add方法,并且需要有无参构造函数。为了简化Add方法与构造函数可以让自定义集合契约直接实现List<T>。

对于自定义集合契约,WCF可以直接使用CollectionDataContract将其标记,泛型类T无需标记为DataContract。如下: 

  1. [CollectionDataContract(Name = "TeacherList", ItemName = "TeacherEntry", Namespace = "cnblogs.com")]  
  2. public class Collection<T> : List<T>  
  3. {  
  4. private readonly IList<Teacher> teachers = new List<Teacher>();  

7、数据契约代理。

数据契约代理实现了IDataContractSurrogate。在WCF中,它可被用于WCF默认的序列器

DataContractSerializer中,用于将数据契约类与其他相似类型的转化。以下实现Contract类型与数据契约Employee之间

的转化。

示例代码如下:

Contract类:

  1. public class Contract  
  2. {  
  3. public string FullName { getset; }  
  4. public string Sex { getset; }  

数据契约Employee:

  1. [DataContract]  
  2. public class Employee  
  3. {  
  4. [DataMember]  
  5. public string FirstName { getset; }  
  6.  
  7. [DataMember]  
  8. public string LastName { getset; }  
  9.  
  10. [DataMember]  
  11. public string Gender { getset; }  

实现IDataContractSurrogate接口:

  1. class ContactSurrogate : IDataContractSurrogate  
  2. {  
  3.  
  4. #region IDataContractSurrogate 成员  
  5.  
  6. public object GetCustomDataToExport(Type clrType, Type dataContractType)  
  7. {  
  8. return null;  
  9. }  
  10.  
  11. public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)  
  12. {  
  13. return null;  
  14. }  
  15.  
  16. public Type GetDataContractType(Type type)  
  17. {  
  18. if (type==typeof(Contract))  
  19. {  
  20. return typeof (Employee);  
  21. }  
  22. return type;  
  23. }  
  24.  
  25. public object GetDeserializedObject(object obj, Type targetType)  
  26. {  
  27. Employee employee = obj as Employee;  
  28. if (employee==null)  
  29. {  
  30. return obj;  
  31. }  
  32. return new Contract {FullName = employee.FirstName + employee.LastName, Sex = employee.Gender};  
  33. }  
  34.  
  35. public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type> customDataTypes)  
  36. {  
  37.  
  38. }  
  39.  
  40. public object GetObjectToSerialize(object obj, Type targetType)  
  41. {  
  42. Contract contract = obj as Contract;  
  43. if (contract == null)  
  44. {  
  45. return obj;  
  46. }  
  47. return new Employee  
  48. {  
  49. FirstName = contract.FullName.Split(" ".ToArray(), StringSplitOptions.None)[0],  
  50. Gender = contract.Sex,  
  51. LastName = contract.FullName.Split(" ".ToArray(), StringSplitOptions.None)[1]  
  52. };  
  53. }  
  54.  
  55. public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)  
  56. {  
  57. return null;  
  58. }  
  59.  
  60. public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)  
  61. {  
  62. return typeDeclaration;  
  63. }  
  64.  
  65. #endregion  

使用ContactSurrogate进行序列化与反序列化的方法:

  1. public static void Serializer<T>(T instance,string fileName,IDataContractSurrogate dataContractSurrogate)  
  2. {  
  3. DataContractSerializer serializer=new DataContractSerializer(typeof(T),null,Int32.MaxValue,false,false,dataContractSurrogate);  
  4. using(XmlWriter xmlWriter=XmlWriter.Create(fileName))  
  5. {  
  6. serializer.WriteObject(xmlWriter, instance);  
  7. }  
  8. Process.Start(fileName);  
  9. }  
  10.  
  11. public static T DeSerializer<T>(string fileName,IDataContractSurrogate dataContractSurrogate)  
  12. {  
  13. DataContractSerializer serializer = new DataContractSerializer(typeof(T), new List<Type>(), Int32.MaxValue, falsefalse, dataContractSurrogate);  
  14. using (XmlReader xmlReader=XmlReader.Create(fileName))  
  15. {  
  16. object obj = serializer.ReadObject(xmlReader);  
  17. return (T) obj;  
  18. }  

现在对数据契约Employee使用Serializer<T>进行序列化,然后将它序列化后的文件使用DeSerializer<T>将它反序

列化成反序列化为Contract对象。

  1. Employee employee = new Employee {FirstName = "yongbo", Gender = "male", LastName = "Tao"};  
  2. ContactSurrogate contactSurrogate = new ContactSurrogate();  
  3. Tools.Serializer(employee, @"C:\DataContractSurrogate.txt", contactSurrogate);  
  4.  
  5. Contract obj = Tools.DeSerializer<Contract>(@"C:\DataContractSurrogate.txt", contactSurrogate);  
  6. 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

WCF

2022-03-02 08:01:31

面试前端开发

2015-04-21 09:28:29

2019-12-03 08:13:06

BDRDR路由器

2019-10-17 15:10:33

PHP程序员Linux

2017-01-15 01:12:40

码农简历专业名词

2020-08-04 07:02:00

TCPIP算法

2022-02-07 00:10:28

Docker容器开发

2010-08-30 19:42:45

DHCP服务器

2009-04-01 11:39:39

视图DB2

2021-06-11 11:42:57

Swift 函数生成器结果生成器

2019-06-06 15:49:53

多线程iOS开发操作

2022-08-03 08:03:03

前端APIjavascript

2021-06-29 15:56:39

MYSQL开发数据库

2020-11-06 00:50:16

JavaClassLoaderJVM

2010-08-17 14:56:00

HCNE认证

2011-04-15 12:25:21

BGP路由

2014-06-10 13:44:58

iOSUIImage知识点

2016-05-30 17:31:34

Spring框架

2010-08-02 11:33:17

IBM DB2
点赞
收藏

51CTO技术栈公众号