ErrorBehavior.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Runtime;
  8. using System.ServiceModel;
  9. using System.ServiceModel.Channels;
  10. using System.ServiceModel.Diagnostics;
  11. using System.ServiceModel.Diagnostics.Application;
  12. class ErrorBehavior
  13. {
  14. IErrorHandler[] handlers;
  15. bool debug;
  16. bool isOnServer;
  17. MessageVersion messageVersion;
  18. internal ErrorBehavior(ChannelDispatcher channelDispatcher)
  19. {
  20. this.handlers = EmptyArray<IErrorHandler>.ToArray(channelDispatcher.ErrorHandlers);
  21. this.debug = channelDispatcher.IncludeExceptionDetailInFaults;
  22. this.isOnServer = channelDispatcher.IsOnServer;
  23. this.messageVersion = channelDispatcher.MessageVersion;
  24. }
  25. void InitializeFault(ref MessageRpc rpc)
  26. {
  27. Exception error = rpc.Error;
  28. FaultException fault = error as FaultException;
  29. if (fault != null)
  30. {
  31. string action;
  32. MessageFault messageFault = rpc.Operation.FaultFormatter.Serialize(fault, out action);
  33. if (action == null)
  34. action = rpc.RequestVersion.Addressing.DefaultFaultAction;
  35. if (messageFault != null)
  36. rpc.FaultInfo.Fault = Message.CreateMessage(rpc.RequestVersion, messageFault, action);
  37. }
  38. }
  39. internal IErrorHandler[] Handlers
  40. {
  41. get
  42. {
  43. return handlers;
  44. }
  45. }
  46. internal void ProvideMessageFault(ref MessageRpc rpc)
  47. {
  48. if (rpc.Error != null)
  49. {
  50. ProvideMessageFaultCore(ref rpc);
  51. }
  52. }
  53. void ProvideMessageFaultCore(ref MessageRpc rpc)
  54. {
  55. if (this.messageVersion != rpc.RequestVersion)
  56. {
  57. Fx.Assert("System.ServiceModel.Dispatcher.ErrorBehavior.ProvideMessageFaultCore(): (this.messageVersion != rpc.RequestVersion)");
  58. }
  59. this.InitializeFault(ref rpc);
  60. this.ProvideFault(rpc.Error, rpc.Channel.GetProperty<FaultConverter>(), ref rpc.FaultInfo);
  61. this.ProvideMessageFaultCoreCoda(ref rpc);
  62. }
  63. void ProvideFaultOfLastResort(Exception error, ref ErrorHandlerFaultInfo faultInfo)
  64. {
  65. if (faultInfo.Fault == null)
  66. {
  67. FaultCode code = new FaultCode(FaultCodeConstants.Codes.InternalServiceFault, FaultCodeConstants.Namespaces.NetDispatch);
  68. code = FaultCode.CreateReceiverFaultCode(code);
  69. string action = FaultCodeConstants.Actions.NetDispatcher;
  70. MessageFault fault;
  71. if (this.debug)
  72. {
  73. faultInfo.DefaultFaultAction = action;
  74. fault = MessageFault.CreateFault(code, new FaultReason(error.Message), new ExceptionDetail(error));
  75. }
  76. else
  77. {
  78. string reason = this.isOnServer ? SR.GetString(SR.SFxInternalServerError) : SR.GetString(SR.SFxInternalCallbackError);
  79. fault = MessageFault.CreateFault(code, new FaultReason(reason));
  80. }
  81. faultInfo.IsConsideredUnhandled = true;
  82. faultInfo.Fault = Message.CreateMessage(this.messageVersion, fault, action);
  83. }
  84. //if this is an InternalServiceFault coming from another service dispatcher we should treat it as unhandled so that the channels are cleaned up
  85. else if (error != null)
  86. {
  87. FaultException e = error as FaultException;
  88. if (e != null && e.Fault != null && e.Fault.Code != null && e.Fault.Code.SubCode != null &&
  89. string.Compare(e.Fault.Code.SubCode.Namespace, FaultCodeConstants.Namespaces.NetDispatch, StringComparison.Ordinal) == 0 &&
  90. string.Compare(e.Fault.Code.SubCode.Name, FaultCodeConstants.Codes.InternalServiceFault, StringComparison.Ordinal) == 0)
  91. {
  92. faultInfo.IsConsideredUnhandled = true;
  93. }
  94. }
  95. }
  96. void ProvideMessageFaultCoreCoda(ref MessageRpc rpc)
  97. {
  98. if (rpc.FaultInfo.Fault.Headers.Action == null)
  99. {
  100. rpc.FaultInfo.Fault.Headers.Action = rpc.RequestVersion.Addressing.DefaultFaultAction;
  101. }
  102. rpc.Reply = rpc.FaultInfo.Fault;
  103. }
  104. internal void ProvideOnlyFaultOfLastResort(ref MessageRpc rpc)
  105. {
  106. this.ProvideFaultOfLastResort(rpc.Error, ref rpc.FaultInfo);
  107. this.ProvideMessageFaultCoreCoda(ref rpc);
  108. }
  109. internal void ProvideFault(Exception e, FaultConverter faultConverter, ref ErrorHandlerFaultInfo faultInfo)
  110. {
  111. ProvideWellKnownFault(e, faultConverter, ref faultInfo);
  112. for (int i = 0; i < this.handlers.Length; i++)
  113. {
  114. Message m = faultInfo.Fault;
  115. handlers[i].ProvideFault(e, this.messageVersion, ref m);
  116. faultInfo.Fault = m;
  117. if (TD.FaultProviderInvokedIsEnabled())
  118. {
  119. TD.FaultProviderInvoked(handlers[i].GetType().FullName, e.Message);
  120. }
  121. }
  122. this.ProvideFaultOfLastResort(e, ref faultInfo);
  123. }
  124. void ProvideWellKnownFault(Exception e, FaultConverter faultConverter, ref ErrorHandlerFaultInfo faultInfo)
  125. {
  126. Message faultMessage;
  127. if (faultConverter != null && faultConverter.TryCreateFaultMessage(e, out faultMessage))
  128. {
  129. faultInfo.Fault = faultMessage;
  130. return;
  131. }
  132. else if (e is NetDispatcherFaultException)
  133. {
  134. NetDispatcherFaultException ndfe = e as NetDispatcherFaultException;
  135. if (this.debug)
  136. {
  137. ExceptionDetail detail = new ExceptionDetail(ndfe);
  138. faultInfo.Fault = Message.CreateMessage(this.messageVersion, MessageFault.CreateFault(ndfe.Code, ndfe.Reason, detail), ndfe.Action);
  139. }
  140. else
  141. {
  142. faultInfo.Fault = Message.CreateMessage(this.messageVersion, ndfe.CreateMessageFault(), ndfe.Action);
  143. }
  144. }
  145. }
  146. internal void HandleError(ref MessageRpc rpc)
  147. {
  148. if (rpc.Error != null)
  149. {
  150. HandleErrorCore(ref rpc);
  151. }
  152. }
  153. void HandleErrorCore(ref MessageRpc rpc)
  154. {
  155. bool handled = HandleErrorCommon(rpc.Error, ref rpc.FaultInfo);
  156. if (handled)
  157. {
  158. rpc.Error = null;
  159. }
  160. }
  161. bool HandleErrorCommon(Exception error, ref ErrorHandlerFaultInfo faultInfo)
  162. {
  163. bool handled;
  164. if (faultInfo.Fault != null // there is a message
  165. && !faultInfo.IsConsideredUnhandled) // and it's not the internal-server-error one
  166. {
  167. handled = true;
  168. }
  169. else
  170. {
  171. handled = false;
  172. }
  173. try
  174. {
  175. if (TD.ServiceExceptionIsEnabled())
  176. {
  177. TD.ServiceException(null, error.ToString(), error.GetType().FullName);
  178. }
  179. for (int i = 0; i < this.handlers.Length; i++)
  180. {
  181. bool handledByThis = handlers[i].HandleError(error);
  182. handled = handledByThis || handled;
  183. if (TD.ErrorHandlerInvokedIsEnabled())
  184. {
  185. TD.ErrorHandlerInvoked(handlers[i].GetType().FullName, handledByThis, error.GetType().FullName);
  186. }
  187. }
  188. }
  189. catch (Exception e)
  190. {
  191. if (Fx.IsFatal(e))
  192. {
  193. throw;
  194. }
  195. throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
  196. }
  197. return handled;
  198. }
  199. internal bool HandleError(Exception error)
  200. {
  201. ErrorHandlerFaultInfo faultInfo = new ErrorHandlerFaultInfo(this.messageVersion.Addressing.DefaultFaultAction);
  202. return HandleError(error, ref faultInfo);
  203. }
  204. internal bool HandleError(Exception error, ref ErrorHandlerFaultInfo faultInfo)
  205. {
  206. return HandleErrorCommon(error, ref faultInfo);
  207. }
  208. internal static bool ShouldRethrowExceptionAsIs(Exception e)
  209. {
  210. return true;
  211. }
  212. internal static bool ShouldRethrowClientSideExceptionAsIs(Exception e)
  213. {
  214. return true;
  215. }
  216. // This ensures that people debugging first-chance Exceptions see this Exception,
  217. // and that the Exception shows up in the trace logs.
  218. internal static void ThrowAndCatch(Exception e, Message message)
  219. {
  220. try
  221. {
  222. if (System.Diagnostics.Debugger.IsAttached)
  223. {
  224. if (message == null)
  225. {
  226. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
  227. }
  228. else
  229. {
  230. throw TraceUtility.ThrowHelperError(e, message);
  231. }
  232. }
  233. else
  234. {
  235. if (message == null)
  236. {
  237. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(e);
  238. }
  239. else
  240. {
  241. TraceUtility.ThrowHelperError(e, message);
  242. }
  243. }
  244. }
  245. catch (Exception e2)
  246. {
  247. if (!object.ReferenceEquals(e, e2))
  248. {
  249. throw;
  250. }
  251. }
  252. }
  253. internal static void ThrowAndCatch(Exception e)
  254. {
  255. ThrowAndCatch(e, null);
  256. }
  257. }
  258. }