OperationInvokerHandler.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.ServiceModel.Channels;
  5. using System.ServiceModel;
  6. using System.Reflection;
  7. using System.Threading;
  8. namespace System.ServiceModel.Dispatcher
  9. {
  10. internal class OperationInvokerHandler : BaseRequestProcessorHandler
  11. {
  12. IDuplexChannel duplex;
  13. public OperationInvokerHandler (IChannel channel)
  14. {
  15. duplex = channel as IDuplexChannel;
  16. }
  17. protected override bool ProcessRequest (MessageProcessingContext mrc)
  18. {
  19. RequestContext rc = mrc.RequestContext;
  20. DispatchRuntime dispatchRuntime = mrc.OperationContext.EndpointDispatcher.DispatchRuntime;
  21. DispatchOperation operation = GetOperation (mrc.IncomingMessage, dispatchRuntime);
  22. mrc.Operation = operation;
  23. try {
  24. DoProcessRequest (mrc);
  25. if (!mrc.Operation.IsOneWay)
  26. Reply (mrc, true);
  27. } catch (TargetInvocationException ex) {
  28. mrc.ReplyMessage = BuildExceptionMessage (mrc, ex.InnerException,
  29. dispatchRuntime.ChannelDispatcher.IncludeExceptionDetailInFaults);
  30. if (!mrc.Operation.IsOneWay)
  31. Reply (mrc, true);
  32. ProcessCustomErrorHandlers (mrc, ex);
  33. }
  34. return false;
  35. }
  36. void DoProcessRequest (MessageProcessingContext mrc)
  37. {
  38. DispatchOperation operation = mrc.Operation;
  39. Message req = mrc.IncomingMessage;
  40. object instance = mrc.InstanceContext.GetServiceInstance(req);
  41. object [] parameters, outParams;
  42. BuildInvokeParams (mrc, out parameters);
  43. if (operation.Invoker.IsSynchronous) {
  44. object result = operation.Invoker.Invoke (instance, parameters, out outParams);
  45. HandleInvokeResult (mrc, outParams, result);
  46. } else {
  47. var ar = operation.Invoker.InvokeBegin (instance, parameters, null, null);
  48. object result = operation.Invoker.InvokeEnd (instance, out outParams, ar);
  49. HandleInvokeResult (mrc, outParams, result);
  50. }
  51. }
  52. void Reply (MessageProcessingContext mrc, bool useTimeout)
  53. {
  54. if (duplex != null)
  55. mrc.Reply (duplex, useTimeout);
  56. else
  57. mrc.Reply (useTimeout);
  58. }
  59. DispatchOperation GetOperation (Message input, DispatchRuntime dispatchRuntime)
  60. {
  61. if (dispatchRuntime.OperationSelector != null) {
  62. string name = dispatchRuntime.OperationSelector.SelectOperation (ref input);
  63. foreach (DispatchOperation d in dispatchRuntime.Operations)
  64. if (d.Name == name)
  65. return d;
  66. } else {
  67. string action = input.Headers.Action;
  68. foreach (DispatchOperation d in dispatchRuntime.Operations)
  69. if (d.Action == action)
  70. return d;
  71. }
  72. return dispatchRuntime.UnhandledDispatchOperation;
  73. }
  74. void HandleInvokeResult (MessageProcessingContext mrc, object [] outputs, object result)
  75. {
  76. DispatchOperation operation = mrc.Operation;
  77. mrc.EventsHandler.AfterInvoke (operation);
  78. if (operation.IsOneWay)
  79. return;
  80. Message res = null;
  81. if (operation.SerializeReply)
  82. res = operation.Formatter.SerializeReply (
  83. mrc.OperationContext.EndpointDispatcher.ChannelDispatcher.MessageVersion, outputs, result);
  84. else
  85. res = (Message) result;
  86. res.Headers.CopyHeadersFrom (mrc.OperationContext.OutgoingMessageHeaders);
  87. res.Properties.CopyProperties (mrc.OperationContext.OutgoingMessageProperties);
  88. mrc.ReplyMessage = res;
  89. }
  90. void BuildInvokeParams (MessageProcessingContext mrc, out object [] parameters)
  91. {
  92. DispatchOperation operation = mrc.Operation;
  93. EnsureValid (operation);
  94. if (operation.DeserializeRequest) {
  95. parameters = operation.Invoker.AllocateInputs ();
  96. operation.Formatter.DeserializeRequest (mrc.IncomingMessage, parameters);
  97. } else
  98. parameters = new object [] { mrc.IncomingMessage };
  99. mrc.EventsHandler.BeforeInvoke (operation);
  100. }
  101. void ProcessCustomErrorHandlers (MessageProcessingContext mrc, Exception ex)
  102. {
  103. var dr = mrc.OperationContext.EndpointDispatcher.DispatchRuntime;
  104. bool shutdown = false;
  105. foreach (var eh in dr.ChannelDispatcher.ErrorHandlers)
  106. shutdown |= eh.HandleError (ex);
  107. if (shutdown)
  108. ProcessSessionErrorShutdown (mrc);
  109. }
  110. void ProcessSessionErrorShutdown (MessageProcessingContext mrc)
  111. {
  112. var dr = mrc.OperationContext.EndpointDispatcher.DispatchRuntime;
  113. var session = mrc.OperationContext.Channel.InputSession;
  114. var dcc = mrc.OperationContext.Channel as IDuplexContextChannel;
  115. if (session == null || dcc == null)
  116. return;
  117. foreach (var h in dr.InputSessionShutdownHandlers)
  118. h.ChannelFaulted (dcc);
  119. }
  120. Message BuildExceptionMessage (MessageProcessingContext mrc, Exception ex, bool includeDetailsInFault)
  121. {
  122. var dr = mrc.OperationContext.EndpointDispatcher.DispatchRuntime;
  123. var cd = dr.ChannelDispatcher;
  124. Message msg = null;
  125. foreach (var eh in cd.ErrorHandlers)
  126. eh.ProvideFault (ex, cd.MessageVersion, ref msg);
  127. if (msg != null)
  128. return msg;
  129. var req = mrc.IncomingMessage;
  130. // FIXME: set correct name
  131. FaultCode fc = new FaultCode (
  132. "InternalServiceFault",
  133. req.Version.Addressing.Namespace);
  134. if (includeDetailsInFault) {
  135. return Message.CreateMessage (req.Version, fc, ex.Message, new ExceptionDetail (ex), req.Headers.Action);
  136. }
  137. string faultString =
  138. @"The server was unable to process the request due to an internal error. The server may be able to return exception details (it depends on the server settings).";
  139. return Message.CreateMessage (req.Version, fc, faultString, req.Headers.Action);
  140. }
  141. void EnsureValid (DispatchOperation operation)
  142. {
  143. if (operation.Invoker == null)
  144. throw new InvalidOperationException (String.Format ("DispatchOperation '{0}' for contract '{1}' requires Invoker.", operation.Name, operation.Parent.EndpointDispatcher.ContractName));
  145. if ((operation.DeserializeRequest || operation.SerializeReply) && operation.Formatter == null)
  146. throw new InvalidOperationException ("The DispatchOperation '" + operation.Name + "' requires Formatter, since DeserializeRequest and SerializeReply are not both false.");
  147. }
  148. }
  149. }