2 using System
.Collections
.Generic
;
4 using System
.ServiceModel
.Channels
;
5 using System
.ServiceModel
;
6 using System
.Reflection
;
7 using System
.Threading
;
9 namespace System
.ServiceModel
.Dispatcher
11 internal class OperationInvokerHandler
: BaseRequestProcessorHandler
13 IDuplexChannel duplex
;
15 public OperationInvokerHandler (IChannel channel
)
17 duplex
= channel
as IDuplexChannel
;
20 protected override bool ProcessRequest (MessageProcessingContext mrc
)
22 RequestContext rc
= mrc
.RequestContext
;
23 DispatchRuntime dispatchRuntime
= mrc
.OperationContext
.EndpointDispatcher
.DispatchRuntime
;
24 DispatchOperation operation
= GetOperation (mrc
.IncomingMessage
, dispatchRuntime
);
25 mrc
.Operation
= operation
;
27 DoProcessRequest (mrc
);
28 if (!mrc
.Operation
.IsOneWay
)
30 } catch (TargetInvocationException ex
) {
31 mrc
.ReplyMessage
= BuildExceptionMessage (mrc
, ex
.InnerException
,
32 dispatchRuntime
.ChannelDispatcher
.IncludeExceptionDetailInFaults
);
33 if (!mrc
.Operation
.IsOneWay
)
35 ProcessCustomErrorHandlers (mrc
, ex
);
40 void DoProcessRequest (MessageProcessingContext mrc
)
42 DispatchOperation operation
= mrc
.Operation
;
43 Message req
= mrc
.IncomingMessage
;
44 object instance
= mrc
.InstanceContext
.GetServiceInstance(req
);
45 object [] parameters
, outParams
;
46 BuildInvokeParams (mrc
, out parameters
);
48 if (operation
.Invoker
.IsSynchronous
) {
49 object result
= operation
.Invoker
.Invoke (instance
, parameters
, out outParams
);
50 HandleInvokeResult (mrc
, outParams
, result
);
52 var ar
= operation
.Invoker
.InvokeBegin (instance
, parameters
, null, null);
53 object result
= operation
.Invoker
.InvokeEnd (instance
, out outParams
, ar
);
54 HandleInvokeResult (mrc
, outParams
, result
);
58 void Reply (MessageProcessingContext mrc
, bool useTimeout
)
61 mrc
.Reply (duplex
, useTimeout
);
63 mrc
.Reply (useTimeout
);
66 DispatchOperation
GetOperation (Message input
, DispatchRuntime dispatchRuntime
)
68 if (dispatchRuntime
.OperationSelector
!= null) {
69 string name
= dispatchRuntime
.OperationSelector
.SelectOperation (ref input
);
70 foreach (DispatchOperation d
in dispatchRuntime
.Operations
)
74 string action
= input
.Headers
.Action
;
75 foreach (DispatchOperation d
in dispatchRuntime
.Operations
)
76 if (d
.Action
== action
)
79 return dispatchRuntime
.UnhandledDispatchOperation
;
82 void HandleInvokeResult (MessageProcessingContext mrc
, object [] outputs
, object result
)
84 DispatchOperation operation
= mrc
.Operation
;
85 mrc
.EventsHandler
.AfterInvoke (operation
);
87 if (operation
.IsOneWay
)
91 if (operation
.SerializeReply
)
92 res
= operation
.Formatter
.SerializeReply (
93 mrc
.OperationContext
.EndpointDispatcher
.ChannelDispatcher
.MessageVersion
, outputs
, result
);
95 res
= (Message
) result
;
96 res
.Headers
.CopyHeadersFrom (mrc
.OperationContext
.OutgoingMessageHeaders
);
97 res
.Properties
.CopyProperties (mrc
.OperationContext
.OutgoingMessageProperties
);
98 mrc
.ReplyMessage
= res
;
101 void BuildInvokeParams (MessageProcessingContext mrc
, out object [] parameters
)
103 DispatchOperation operation
= mrc
.Operation
;
104 EnsureValid (operation
);
106 if (operation
.DeserializeRequest
) {
107 parameters
= operation
.Invoker
.AllocateInputs ();
108 operation
.Formatter
.DeserializeRequest (mrc
.IncomingMessage
, parameters
);
110 parameters
= new object [] { mrc.IncomingMessage }
;
112 mrc
.EventsHandler
.BeforeInvoke (operation
);
115 void ProcessCustomErrorHandlers (MessageProcessingContext mrc
, Exception ex
)
117 var dr
= mrc
.OperationContext
.EndpointDispatcher
.DispatchRuntime
;
118 bool shutdown
= false;
119 foreach (var eh
in dr
.ChannelDispatcher
.ErrorHandlers
)
120 shutdown
|= eh
.HandleError (ex
);
122 ProcessSessionErrorShutdown (mrc
);
125 void ProcessSessionErrorShutdown (MessageProcessingContext mrc
)
127 var dr
= mrc
.OperationContext
.EndpointDispatcher
.DispatchRuntime
;
128 var session
= mrc
.OperationContext
.Channel
.InputSession
;
129 var dcc
= mrc
.OperationContext
.Channel
as IDuplexContextChannel
;
130 if (session
== null || dcc
== null)
132 foreach (var h
in dr
.InputSessionShutdownHandlers
)
133 h
.ChannelFaulted (dcc
);
136 Message
BuildExceptionMessage (MessageProcessingContext mrc
, Exception ex
, bool includeDetailsInFault
)
138 var dr
= mrc
.OperationContext
.EndpointDispatcher
.DispatchRuntime
;
139 var cd
= dr
.ChannelDispatcher
;
141 foreach (var eh
in cd
.ErrorHandlers
)
142 eh
.ProvideFault (ex
, cd
.MessageVersion
, ref msg
);
146 var req
= mrc
.IncomingMessage
;
148 var fe
= ex
as FaultException
;
149 if (fe
!= null && fe
.GetType ().IsGenericType
) {
150 var t
= fe
.GetType ().GetGenericArguments () [0];
151 foreach (var fci
in mrc
.Operation
.FaultContractInfos
)
153 return Message
.CreateMessage (req
.Version
, fe
.CreateMessageFault (), fci
.Action
);
156 // FIXME: set correct name
157 FaultCode fc
= new FaultCode (
158 "InternalServiceFault",
159 req
.Version
.Addressing
.Namespace
);
162 if (includeDetailsInFault
) {
163 return Message
.CreateMessage (req
.Version
, fc
, ex
.Message
, new ExceptionDetail (ex
), req
.Headers
.Action
);
167 @"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).";
168 return Message
.CreateMessage (req
.Version
, fc
, faultString
, req
.Headers
.Action
);
171 void EnsureValid (DispatchOperation operation
)
173 if (operation
.Invoker
== null)
174 throw new InvalidOperationException (String
.Format ("DispatchOperation '{0}' for contract '{1}' requires Invoker.", operation
.Name
, operation
.Parent
.EndpointDispatcher
.ContractName
));
175 if ((operation
.DeserializeRequest
|| operation
.SerializeReply
) && operation
.Formatter
== null)
176 throw new InvalidOperationException ("The DispatchOperation '" + operation
.Name
+ "' requires Formatter, since DeserializeRequest and SerializeReply are not both false.");