1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 5 namespace System.ServiceModel.Dispatcher 6 { 7 using System; 8 using System.Collections.ObjectModel; 9 using System.Reflection; 10 using System.Runtime; 11 using System.Runtime.Remoting.Messaging; 12 using System.Security; 13 using System.ServiceModel; 14 using System.ServiceModel.Channels; 15 using System.ServiceModel.Description; 16 using System.ServiceModel.Diagnostics; 17 using System.ServiceModel.Diagnostics.Application; 18 19 class ProxyOperationRuntime 20 { 21 static internal readonly ParameterInfo[] NoParams = new ParameterInfo[0]; 22 static internal readonly object[] EmptyArray = new object[0]; 23 24 readonly IClientMessageFormatter formatter; 25 readonly bool isInitiating; 26 readonly bool isOneWay; 27 readonly bool isTerminating; 28 readonly bool isSessionOpenNotificationEnabled; 29 readonly string name; 30 readonly IParameterInspector[] parameterInspectors; 31 readonly IClientFaultFormatter faultFormatter; 32 readonly ImmutableClientRuntime parent; 33 bool serializeRequest; 34 bool deserializeReply; 35 string action; 36 string replyAction; 37 38 MethodInfo beginMethod; 39 MethodInfo syncMethod; 40 MethodInfo taskMethod; 41 ParameterInfo[] inParams; 42 ParameterInfo[] outParams; 43 ParameterInfo[] endOutParams; 44 ParameterInfo returnParam; 45 ProxyOperationRuntime(ClientOperation operation, ImmutableClientRuntime parent)46 internal ProxyOperationRuntime(ClientOperation operation, ImmutableClientRuntime parent) 47 { 48 if (operation == null) 49 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operation"); 50 if (parent == null) 51 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parent"); 52 53 this.parent = parent; 54 this.formatter = operation.Formatter; 55 this.isInitiating = operation.IsInitiating; 56 this.isOneWay = operation.IsOneWay; 57 this.isTerminating = operation.IsTerminating; 58 this.isSessionOpenNotificationEnabled = operation.IsSessionOpenNotificationEnabled; 59 this.name = operation.Name; 60 this.parameterInspectors = EmptyArray<IParameterInspector>.ToArray(operation.ParameterInspectors); 61 this.faultFormatter = operation.FaultFormatter; 62 this.serializeRequest = operation.SerializeRequest; 63 this.deserializeReply = operation.DeserializeReply; 64 this.action = operation.Action; 65 this.replyAction = operation.ReplyAction; 66 this.beginMethod = operation.BeginMethod; 67 this.syncMethod = operation.SyncMethod; 68 this.taskMethod = operation.TaskMethod; 69 this.TaskTResult = operation.TaskTResult; 70 71 if (this.beginMethod != null) 72 { 73 this.inParams = ServiceReflector.GetInputParameters(this.beginMethod, true); 74 if (this.syncMethod != null) 75 { 76 this.outParams = ServiceReflector.GetOutputParameters(this.syncMethod, false); 77 } 78 else 79 { 80 this.outParams = NoParams; 81 } 82 this.endOutParams = ServiceReflector.GetOutputParameters(operation.EndMethod, true); 83 this.returnParam = operation.EndMethod.ReturnParameter; 84 } 85 else if (this.syncMethod != null) 86 { 87 this.inParams = ServiceReflector.GetInputParameters(this.syncMethod, false); 88 this.outParams = ServiceReflector.GetOutputParameters(this.syncMethod, false); 89 this.returnParam = this.syncMethod.ReturnParameter; 90 } 91 92 if (this.formatter == null && (serializeRequest || deserializeReply)) 93 { 94 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ClientRuntimeRequiresFormatter0, this.name))); 95 } 96 } 97 98 internal string Action 99 { 100 get { return this.action; } 101 } 102 103 internal IClientFaultFormatter FaultFormatter 104 { 105 get { return this.faultFormatter; } 106 } 107 108 internal bool IsInitiating 109 { 110 get { return this.isInitiating; } 111 } 112 113 internal bool IsOneWay 114 { 115 get { return this.isOneWay; } 116 } 117 118 internal bool IsTerminating 119 { 120 get { return this.isTerminating; } 121 } 122 123 internal bool IsSessionOpenNotificationEnabled 124 { 125 get { return this.isSessionOpenNotificationEnabled; } 126 } 127 128 internal string Name 129 { 130 get { return this.name; } 131 } 132 133 internal ImmutableClientRuntime Parent 134 { 135 get { return this.parent; } 136 } 137 138 internal string ReplyAction 139 { 140 get { return this.replyAction; } 141 } 142 143 internal bool DeserializeReply 144 { 145 get { return this.deserializeReply; } 146 } 147 148 internal bool SerializeRequest 149 { 150 get { return this.serializeRequest; } 151 } 152 153 internal Type TaskTResult 154 { 155 get; 156 set; 157 } 158 AfterReply(ref ProxyRpc rpc)159 internal void AfterReply(ref ProxyRpc rpc) 160 { 161 if (!this.isOneWay) 162 { 163 Message reply = rpc.Reply; 164 165 if (this.deserializeReply) 166 { 167 if (TD.ClientFormatterDeserializeReplyStartIsEnabled()) 168 { 169 TD.ClientFormatterDeserializeReplyStart(rpc.EventTraceActivity); 170 } 171 172 rpc.ReturnValue = this.formatter.DeserializeReply(reply, rpc.OutputParameters); 173 174 if (TD.ClientFormatterDeserializeReplyStopIsEnabled()) 175 { 176 TD.ClientFormatterDeserializeReplyStop(rpc.EventTraceActivity); 177 } 178 179 } 180 else 181 { 182 rpc.ReturnValue = reply; 183 } 184 185 int offset = this.parent.ParameterInspectorCorrelationOffset; 186 try 187 { 188 for (int i = parameterInspectors.Length - 1; i >= 0; i--) 189 { 190 this.parameterInspectors[i].AfterCall(this.name, 191 rpc.OutputParameters, 192 rpc.ReturnValue, 193 rpc.Correlation[offset + i]); 194 if (TD.ClientParameterInspectorAfterCallInvokedIsEnabled()) 195 { 196 TD.ClientParameterInspectorAfterCallInvoked(rpc.EventTraceActivity, this.parameterInspectors[i].GetType().FullName); 197 } 198 } 199 } 200 catch (Exception e) 201 { 202 if (Fx.IsFatal(e)) 203 { 204 throw; 205 } 206 if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e)) 207 { 208 throw; 209 } 210 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); 211 } 212 213 if (parent.ValidateMustUnderstand) 214 { 215 Collection<MessageHeaderInfo> headersNotUnderstood = reply.Headers.GetHeadersNotUnderstood(); 216 if (headersNotUnderstood != null && headersNotUnderstood.Count > 0) 217 { 218 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.SFxHeaderNotUnderstood, headersNotUnderstood[0].Name, headersNotUnderstood[0].Namespace))); 219 } 220 } 221 } 222 } 223 BeforeRequest(ref ProxyRpc rpc)224 internal void BeforeRequest(ref ProxyRpc rpc) 225 { 226 int offset = this.parent.ParameterInspectorCorrelationOffset; 227 try 228 { 229 for (int i = 0; i < parameterInspectors.Length; i++) 230 { 231 rpc.Correlation[offset + i] = this.parameterInspectors[i].BeforeCall(this.name, rpc.InputParameters); 232 if (TD.ClientParameterInspectorBeforeCallInvokedIsEnabled()) 233 { 234 TD.ClientParameterInspectorBeforeCallInvoked(rpc.EventTraceActivity, this.parameterInspectors[i].GetType().FullName); 235 } 236 } 237 } 238 catch (Exception e) 239 { 240 if (Fx.IsFatal(e)) 241 { 242 throw; 243 } 244 if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e)) 245 { 246 throw; 247 } 248 throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); 249 } 250 251 if (this.serializeRequest) 252 { 253 if (TD.ClientFormatterSerializeRequestStartIsEnabled()) 254 { 255 TD.ClientFormatterSerializeRequestStart(rpc.EventTraceActivity); 256 } 257 258 rpc.Request = this.formatter.SerializeRequest(rpc.MessageVersion, rpc.InputParameters); 259 260 261 262 if (TD.ClientFormatterSerializeRequestStopIsEnabled()) 263 { 264 TD.ClientFormatterSerializeRequestStop(rpc.EventTraceActivity); 265 } 266 } 267 else 268 { 269 if (rpc.InputParameters[0] == null) 270 { 271 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxProxyRuntimeMessageCannotBeNull, this.name))); 272 } 273 274 rpc.Request = (Message)rpc.InputParameters[0]; 275 if (!IsValidAction(rpc.Request, Action)) 276 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidRequestAction, this.Name, rpc.Request.Headers.Action ?? "{NULL}", this.Action))); 277 } 278 } 279 GetDefaultParameterValue(Type parameterType)280 internal static object GetDefaultParameterValue(Type parameterType) 281 { 282 return (parameterType.IsValueType && parameterType != typeof(void)) ? Activator.CreateInstance(parameterType) : null; 283 } 284 285 [SecurityCritical] IsSyncCall(IMethodCallMessage methodCall)286 internal bool IsSyncCall(IMethodCallMessage methodCall) 287 { 288 if (this.syncMethod == null) 289 { 290 return false; 291 } 292 293 return (methodCall.MethodBase.MethodHandle == this.syncMethod.MethodHandle); 294 } 295 296 [SecurityCritical] IsBeginCall(IMethodCallMessage methodCall)297 internal bool IsBeginCall(IMethodCallMessage methodCall) 298 { 299 if (this.beginMethod == null) 300 { 301 return false; 302 } 303 304 return (methodCall.MethodBase.MethodHandle == this.beginMethod.MethodHandle); 305 } 306 307 [SecurityCritical] IsTaskCall(IMethodCallMessage methodCall)308 internal bool IsTaskCall(IMethodCallMessage methodCall) 309 { 310 if (this.taskMethod == null) 311 { 312 return false; 313 } 314 315 return (methodCall.MethodBase.MethodHandle == this.taskMethod.MethodHandle); 316 } 317 318 [SecurityCritical] MapSyncInputs(IMethodCallMessage methodCall, out object[] outs)319 internal object[] MapSyncInputs(IMethodCallMessage methodCall, out object[] outs) 320 { 321 if (this.outParams.Length == 0) 322 { 323 outs = EmptyArray; 324 } 325 else 326 { 327 outs = new object[this.outParams.Length]; 328 } 329 if (this.inParams.Length == 0) 330 return EmptyArray; 331 return methodCall.InArgs; 332 } 333 334 [SecurityCritical] MapAsyncBeginInputs(IMethodCallMessage methodCall, out AsyncCallback callback, out object asyncState)335 internal object[] MapAsyncBeginInputs(IMethodCallMessage methodCall, out AsyncCallback callback, out object asyncState) 336 { 337 object[] ins; 338 if (this.inParams.Length == 0) 339 { 340 ins = EmptyArray; 341 } 342 else 343 { 344 ins = new object[this.inParams.Length]; 345 } 346 347 object[] args = methodCall.Args; 348 for (int i = 0; i < ins.Length; i++) 349 { 350 ins[i] = args[this.inParams[i].Position]; 351 } 352 353 callback = args[methodCall.ArgCount - 2] as AsyncCallback; 354 asyncState = args[methodCall.ArgCount - 1]; 355 return ins; 356 } 357 358 [SecurityCritical] MapAsyncEndInputs(IMethodCallMessage methodCall, out IAsyncResult result, out object[] outs)359 internal void MapAsyncEndInputs(IMethodCallMessage methodCall, out IAsyncResult result, out object[] outs) 360 { 361 outs = new object[this.endOutParams.Length]; 362 result = methodCall.Args[methodCall.ArgCount - 1] as IAsyncResult; 363 } 364 365 [SecurityCritical] MapSyncOutputs(IMethodCallMessage methodCall, object[] outs, ref object ret)366 internal object[] MapSyncOutputs(IMethodCallMessage methodCall, object[] outs, ref object ret) 367 { 368 return MapOutputs(this.outParams, methodCall, outs, ref ret); 369 } 370 371 [SecurityCritical] MapAsyncOutputs(IMethodCallMessage methodCall, object[] outs, ref object ret)372 internal object[] MapAsyncOutputs(IMethodCallMessage methodCall, object[] outs, ref object ret) 373 { 374 return MapOutputs(this.endOutParams, methodCall, outs, ref ret); 375 } 376 377 [SecurityCritical] MapOutputs(ParameterInfo[] parameters, IMethodCallMessage methodCall, object[] outs, ref object ret)378 object[] MapOutputs(ParameterInfo[] parameters, IMethodCallMessage methodCall, object[] outs, ref object ret) 379 { 380 if (ret == null && this.returnParam != null) 381 { 382 ret = GetDefaultParameterValue(TypeLoader.GetParameterType(this.returnParam)); 383 } 384 385 if (parameters.Length == 0) 386 { 387 return null; 388 } 389 390 object[] args = methodCall.Args; 391 for (int i = 0; i < parameters.Length; i++) 392 { 393 if (outs[i] == null) 394 { 395 // the RealProxy infrastructure requires a default value for value types 396 args[parameters[i].Position] = GetDefaultParameterValue(TypeLoader.GetParameterType(parameters[i])); 397 } 398 else 399 { 400 args[parameters[i].Position] = outs[i]; 401 } 402 } 403 404 return args; 405 } 406 IsValidAction(Message message, string action)407 static internal bool IsValidAction(Message message, string action) 408 { 409 if (message == null) 410 { 411 return false; 412 } 413 414 if (message.IsFault) 415 { 416 return true; 417 } 418 419 if (action == MessageHeaders.WildcardAction) 420 { 421 return true; 422 } 423 424 return (String.CompareOrdinal(message.Headers.Action, action) == 0); 425 } 426 } 427 } 428