FaultFormatter.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Text;
  7. using System.ServiceModel.Channels;
  8. using System.ServiceModel.Description;
  9. using System.Runtime.Serialization;
  10. using System.Xml;
  11. using System.Reflection;
  12. using System.Diagnostics;
  13. using System.Runtime;
  14. namespace System.ServiceModel.Dispatcher
  15. {
  16. class FaultFormatter : IClientFaultFormatter, IDispatchFaultFormatter
  17. {
  18. FaultContractInfo[] faultContractInfos;
  19. internal FaultFormatter(Type[] detailTypes)
  20. {
  21. List<FaultContractInfo> faultContractInfoList = new List<FaultContractInfo>();
  22. for (int i = 0; i < detailTypes.Length; i++)
  23. faultContractInfoList.Add(new FaultContractInfo(MessageHeaders.WildcardAction, detailTypes[i]));
  24. AddInfrastructureFaults(faultContractInfoList);
  25. faultContractInfos = GetSortedArray(faultContractInfoList);
  26. }
  27. internal FaultFormatter(SynchronizedCollection<FaultContractInfo> faultContractInfoCollection)
  28. {
  29. List<FaultContractInfo> faultContractInfoList;
  30. lock (faultContractInfoCollection.SyncRoot)
  31. {
  32. faultContractInfoList = new List<FaultContractInfo>(faultContractInfoCollection);
  33. }
  34. AddInfrastructureFaults(faultContractInfoList);
  35. this.faultContractInfos = GetSortedArray(faultContractInfoList);
  36. }
  37. public MessageFault Serialize(FaultException faultException, out string action)
  38. {
  39. XmlObjectSerializer serializer = null;
  40. Type detailType = null;
  41. string faultExceptionAction = action = faultException.Action;
  42. Type faultExceptionOfT = null;
  43. for (Type faultType = faultException.GetType(); faultType != typeof(FaultException); faultType = faultType.BaseType)
  44. {
  45. if (faultType.IsGenericType && (faultType.GetGenericTypeDefinition() == typeof(FaultException<>)))
  46. {
  47. faultExceptionOfT = faultType;
  48. break;
  49. }
  50. }
  51. if (faultExceptionOfT != null)
  52. {
  53. detailType = faultExceptionOfT.GetGenericArguments()[0];
  54. serializer = GetSerializer(detailType, faultExceptionAction, out action);
  55. }
  56. return CreateMessageFault(serializer, faultException, detailType);
  57. }
  58. public FaultException Deserialize(MessageFault messageFault, string action)
  59. {
  60. if (!messageFault.HasDetail)
  61. return new FaultException(messageFault, action);
  62. return CreateFaultException(messageFault, action);
  63. }
  64. protected virtual XmlObjectSerializer GetSerializer(Type detailType, string faultExceptionAction, out string action)
  65. {
  66. action = faultExceptionAction;
  67. FaultContractInfo faultInfo = null;
  68. for (int i = 0; i < faultContractInfos.Length; i++)
  69. {
  70. if (faultContractInfos[i].Detail == detailType)
  71. {
  72. faultInfo = faultContractInfos[i];
  73. break;
  74. }
  75. }
  76. if (faultInfo != null)
  77. {
  78. if (action == null)
  79. action = faultInfo.Action;
  80. return faultInfo.Serializer;
  81. }
  82. else
  83. return DataContractSerializerDefaults.CreateSerializer(detailType, int.MaxValue /* maxItemsInObjectGraph */ );
  84. }
  85. protected virtual FaultException CreateFaultException(MessageFault messageFault, string action)
  86. {
  87. IList<FaultContractInfo> faultInfos;
  88. if (action != null)
  89. {
  90. faultInfos = new List<FaultContractInfo>();
  91. for (int i = 0; i < faultContractInfos.Length; i++)
  92. {
  93. if (faultContractInfos[i].Action == action || faultContractInfos[i].Action == MessageHeaders.WildcardAction)
  94. {
  95. faultInfos.Add(faultContractInfos[i]);
  96. }
  97. }
  98. }
  99. else
  100. {
  101. faultInfos = faultContractInfos;
  102. }
  103. Type detailType = null;
  104. object detailObj = null;
  105. for (int i = 0; i < faultInfos.Count; i++)
  106. {
  107. FaultContractInfo faultInfo = faultInfos[i];
  108. XmlDictionaryReader detailReader = messageFault.GetReaderAtDetailContents();
  109. XmlObjectSerializer serializer = faultInfo.Serializer;
  110. if (serializer.IsStartObject(detailReader))
  111. {
  112. detailType = faultInfo.Detail;
  113. try
  114. {
  115. detailObj = serializer.ReadObject(detailReader);
  116. FaultException faultException = CreateFaultException(messageFault, action,
  117. detailObj, detailType, detailReader);
  118. if (faultException != null)
  119. return faultException;
  120. }
  121. catch (SerializationException)
  122. {
  123. }
  124. }
  125. }
  126. return new FaultException(messageFault, action);
  127. }
  128. protected FaultException CreateFaultException(MessageFault messageFault, string action,
  129. object detailObj, Type detailType, XmlDictionaryReader detailReader)
  130. {
  131. if (!detailReader.EOF)
  132. {
  133. detailReader.MoveToContent();
  134. if (detailReader.NodeType != XmlNodeType.EndElement && !detailReader.EOF)
  135. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.ExtraContentIsPresentInFaultDetail)));
  136. }
  137. bool isDetailObjectValid = true;
  138. if (detailObj == null)
  139. {
  140. isDetailObjectValid = !detailType.IsValueType;
  141. }
  142. else
  143. {
  144. isDetailObjectValid = detailType.IsAssignableFrom(detailObj.GetType());
  145. }
  146. if (isDetailObjectValid)
  147. {
  148. Type knownFaultType = typeof(FaultException<>).MakeGenericType(detailType);
  149. return (FaultException)Activator.CreateInstance(knownFaultType,
  150. detailObj,
  151. messageFault.Reason,
  152. messageFault.Code,
  153. action);
  154. }
  155. return null;
  156. }
  157. static FaultContractInfo[] GetSortedArray(List<FaultContractInfo> faultContractInfoList)
  158. {
  159. FaultContractInfo[] temp = faultContractInfoList.ToArray();
  160. Array.Sort<FaultContractInfo>(temp,
  161. delegate(FaultContractInfo x, FaultContractInfo y)
  162. { return string.CompareOrdinal(x.Action, y.Action); }
  163. );
  164. return temp;
  165. }
  166. static void AddInfrastructureFaults(List<FaultContractInfo> faultContractInfos)
  167. {
  168. faultContractInfos.Add(new FaultContractInfo(FaultCodeConstants.Actions.NetDispatcher, typeof(ExceptionDetail)));
  169. }
  170. static MessageFault CreateMessageFault(XmlObjectSerializer serializer, FaultException faultException, Type detailType)
  171. {
  172. if (detailType == null)
  173. {
  174. if (faultException.Fault != null)
  175. return faultException.Fault;
  176. return MessageFault.CreateFault(faultException.Code, faultException.Reason);
  177. }
  178. Fx.Assert(serializer != null, "");
  179. Type operationFaultType = typeof(OperationFault<>).MakeGenericType(detailType);
  180. return (MessageFault)Activator.CreateInstance(operationFaultType, serializer, faultException);
  181. }
  182. internal class OperationFault<T> : XmlObjectSerializerFault
  183. {
  184. public OperationFault(XmlObjectSerializer serializer, FaultException<T> faultException) :
  185. base(faultException.Code, faultException.Reason,
  186. faultException.Detail,
  187. serializer,
  188. string.Empty/*actor*/,
  189. string.Empty/*node*/)
  190. {
  191. }
  192. }
  193. }
  194. }