1 //---------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //---------------------------------------------------------------- 4 5 6 [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(System.Runtime.FxCop.Category.Performance, 7 System.Runtime.FxCop.Rule.AvoidUncalledPrivateCode, 8 Scope = "member", 9 Target = "System.ServiceModel.Routing.SR.RoutingExtensionNotFound", 10 Justification = "gets called in RoutingService.ctor(). bug in fxcop")] 11 12 namespace System.ServiceModel.Routing 13 { 14 using System; 15 using System.Collections.Generic; 16 using System.Configuration; 17 using System.Diagnostics.CodeAnalysis; 18 using System.Runtime; 19 using System.ServiceModel; 20 using System.ServiceModel.Activation; 21 using System.ServiceModel.Channels; 22 using System.ServiceModel.Description; 23 using System.ServiceModel.Dispatcher; 24 using System.Transactions; 25 using SR2 = System.ServiceModel.Routing.SR; 26 using System.Runtime.Diagnostics; 27 using System.ServiceModel.Diagnostics; 28 29 // Some of the [ServiceBehavior] settings are configured in RoutingBehavior class since 30 // we need to pick the options dynamically based on whether we have transactions or not 31 [SuppressMessage(FxCop.Category.Xaml, FxCop.Rule.TypesMustHaveXamlCallableConstructors)] 32 [SuppressMessage(FxCop.Category.Xaml, FxCop.Rule.TypesShouldHavePublicParameterlessConstructors)] 33 [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any, InstanceContextMode = InstanceContextMode.PerSession, 34 UseSynchronizationContext = false, ValidateMustUnderstand = false)] 35 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 36 public sealed class RoutingService : 37 ISimplexDatagramRouter, 38 ISimplexSessionRouter, 39 IRequestReplyRouter, 40 IDuplexSessionRouter, 41 IDisposable 42 { 43 SessionChannels perMessageChannels; 44 OperationContext operationContext; 45 EventTraceActivity eventTraceActivity; 46 RoutingService()47 RoutingService() 48 { 49 this.SessionMessages = new List<MessageRpc>(1); 50 51 //We only need to call this here if we trace in this method. BeginXXX methods call it again. 52 //FxTrace.Trace.SetAndTraceTransfer(this.ActivityID, true); 53 54 this.operationContext = OperationContext.Current; 55 if (Fx.Trace.IsEtwProviderEnabled) 56 { 57 this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(this.operationContext.IncomingMessage); 58 } 59 60 IContextChannel channel = this.operationContext.Channel; 61 62 ServiceHostBase host = this.operationContext.Host; 63 this.ChannelExtension = channel.Extensions.Find<RoutingChannelExtension>(); 64 if (this.ChannelExtension == null) 65 { 66 throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR2.RoutingExtensionNotFound)); 67 } 68 69 this.RoutingConfig = host.Extensions.Find<RoutingExtension>().RoutingConfiguration; 70 this.RoutingConfig.VerifyConfigured(); 71 this.ChannelExtension.AttachService(this); 72 } 73 74 [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "private setter does get called")] 75 internal RoutingChannelExtension ChannelExtension 76 { 77 get; 78 private set; 79 } 80 81 [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "private setter does get called")] 82 internal RoutingConfiguration RoutingConfig 83 { 84 get; 85 private set; 86 } 87 88 internal CommittableTransaction RetryTransaction 89 { 90 get; 91 private set; 92 } 93 94 internal Exception SessionException 95 { 96 get; 97 set; 98 } 99 100 [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, Justification = "private setter does get called")] 101 internal IList<MessageRpc> SessionMessages 102 { 103 get; 104 private set; 105 } 106 107 Transaction ReceiveTransaction 108 { 109 get; 110 set; 111 } 112 CreateNewTransactionIfNeeded(MessageRpc messageRpc)113 internal void CreateNewTransactionIfNeeded(MessageRpc messageRpc) 114 { 115 if (messageRpc.Transaction != null && this.ChannelExtension.TransactedReceiveEnabled) 116 { 117 if (TD.RoutingServiceUsingExistingTransactionIsEnabled()) 118 { 119 TD.RoutingServiceUsingExistingTransaction(messageRpc.EventTraceActivity, messageRpc.Transaction.TransactionInformation.LocalIdentifier); 120 } 121 Fx.Assert(this.ReceiveTransaction == null, "Should only happen at the start of a session."); 122 this.ReceiveTransaction = messageRpc.Transaction; 123 return; 124 } 125 else if (!this.ChannelExtension.TransactedReceiveEnabled || !this.ChannelExtension.ReceiveContextEnabled) 126 { 127 return; 128 } 129 130 Fx.Assert(this.RetryTransaction == null, "Logic error, we shouldn't be calling CreateNewTransactionIfNeeded if we have a RC Transaction"); 131 132 ChannelDispatcher channelDispatcher = this.operationContext.EndpointDispatcher.ChannelDispatcher; 133 TimeSpan timeout = channelDispatcher.TransactionTimeout; 134 IsolationLevel isolation = channelDispatcher.TransactionIsolationLevel; 135 TransactionOptions options = new TransactionOptions(); 136 if (timeout > TimeSpan.Zero) 137 { 138 options.Timeout = timeout; 139 } 140 if (isolation != IsolationLevel.Unspecified) 141 { 142 options.IsolationLevel = isolation; 143 } 144 145 this.RetryTransaction = new CommittableTransaction(options); 146 if (TD.RoutingServiceCreatingTransactionIsEnabled()) 147 { 148 TD.RoutingServiceCreatingTransaction(messageRpc.EventTraceActivity, this.RetryTransaction.TransactionInformation.LocalIdentifier); 149 } 150 } 151 GetSessionChannels(bool impersonating)152 internal SessionChannels GetSessionChannels(bool impersonating) 153 { 154 if (impersonating && !this.ChannelExtension.HasSession) 155 { 156 return this.perMessageChannels; 157 } 158 else 159 { 160 return this.ChannelExtension.SessionChannels; 161 } 162 } 163 GetOrCreateClient(RoutingEndpointTrait endpointTrait, bool impersonating)164 internal IRoutingClient GetOrCreateClient<TContract>(RoutingEndpointTrait endpointTrait, bool impersonating) 165 { 166 if (impersonating && !this.ChannelExtension.HasSession) 167 { 168 if (this.perMessageChannels == null) 169 { 170 this.perMessageChannels = new SessionChannels(this.ChannelExtension.ActivityID); 171 } 172 return this.perMessageChannels.GetOrCreateClient<TContract>(endpointTrait, this, impersonating); 173 } 174 else 175 { 176 return this.ChannelExtension.SessionChannels.GetOrCreateClient<TContract>(endpointTrait, this, impersonating); 177 } 178 } 179 GetTransactionForSending(MessageRpc messageRpc)180 internal Transaction GetTransactionForSending(MessageRpc messageRpc) 181 { 182 if (messageRpc != null && messageRpc.Transaction != null) 183 { 184 return messageRpc.Transaction; 185 } 186 if (this.ReceiveTransaction != null) 187 { 188 //This is the transaction used for the receive, we cannot perform error handling since we 189 //didn't create it. 190 return this.ReceiveTransaction; 191 } 192 else 193 { 194 //This could be null, indicating non-transactional behavior 195 return this.RetryTransaction; 196 } 197 } 198 IDisposable.Dispose()199 void IDisposable.Dispose() 200 { 201 if (this.perMessageChannels != null) 202 { 203 //This is for impersonation, thus it's supposed to complete sync 204 IAsyncResult result = this.perMessageChannels.BeginClose(this.ChannelExtension.OperationTimeout, null, null); 205 this.perMessageChannels.EndClose(result); 206 this.perMessageChannels = null; 207 } 208 } 209 ResetSession()210 internal void ResetSession() 211 { 212 //Are we in a transactional error handling case (i.e. ReceiveContext)? 213 if (this.RetryTransaction != null) 214 { 215 if (this.ChannelExtension.HasSession) 216 { 217 this.ChannelExtension.SessionChannels.AbortAll(); 218 } 219 220 RoutingUtilities.SafeRollbackTransaction(this.RetryTransaction); 221 this.RetryTransaction = null; 222 } 223 } 224 225 [OperationBehavior(Impersonation = ImpersonationOption.Allowed)] ISimplexSessionRouter.BeginProcessMessage(Message message, AsyncCallback callback, object state)226 IAsyncResult ISimplexSessionRouter.BeginProcessMessage(Message message, AsyncCallback callback, object state) 227 { 228 return this.BeginProcessMessage<ISimplexSessionRouter>(message, callback, state); 229 } 230 ISimplexSessionRouter.EndProcessMessage(IAsyncResult result)231 void ISimplexSessionRouter.EndProcessMessage(IAsyncResult result) 232 { 233 this.EndProcessMessage<ISimplexSessionRouter>(result); 234 } 235 236 [OperationBehavior(Impersonation = ImpersonationOption.Allowed)] IRequestReplyRouter.BeginProcessRequest(Message message, AsyncCallback callback, object state)237 IAsyncResult IRequestReplyRouter.BeginProcessRequest(Message message, AsyncCallback callback, object state) 238 { 239 return this.BeginProcessRequest<IRequestReplyRouter>(message, callback, state); 240 } 241 IRequestReplyRouter.EndProcessRequest(IAsyncResult result)242 Message IRequestReplyRouter.EndProcessRequest(IAsyncResult result) 243 { 244 return this.EndProcessRequest<IRequestReplyRouter>(result); 245 } 246 247 [OperationBehavior(Impersonation = ImpersonationOption.Allowed)] IDuplexSessionRouter.BeginProcessMessage(Message message, AsyncCallback callback, object state)248 IAsyncResult IDuplexSessionRouter.BeginProcessMessage(Message message, AsyncCallback callback, object state) 249 { 250 return this.BeginProcessMessage<IDuplexSessionRouter>(message, callback, state); 251 } 252 IDuplexSessionRouter.EndProcessMessage(IAsyncResult result)253 void IDuplexSessionRouter.EndProcessMessage(IAsyncResult result) 254 { 255 this.EndProcessMessage<IDuplexSessionRouter>(result); 256 } 257 258 [OperationBehavior(Impersonation = ImpersonationOption.Allowed)] ISimplexDatagramRouter.BeginProcessMessage(Message message, AsyncCallback callback, object state)259 IAsyncResult ISimplexDatagramRouter.BeginProcessMessage(Message message, AsyncCallback callback, object state) 260 { 261 return this.BeginProcessMessage<ISimplexDatagramRouter>(message, callback, state); 262 } 263 ISimplexDatagramRouter.EndProcessMessage(IAsyncResult result)264 void ISimplexDatagramRouter.EndProcessMessage(IAsyncResult result) 265 { 266 this.EndProcessMessage<ISimplexDatagramRouter>(result); 267 } 268 BeginProcessMessage(Message message, AsyncCallback callback, object state)269 IAsyncResult BeginProcessMessage<TContract>(Message message, AsyncCallback callback, object state) 270 { 271 try 272 { 273 FxTrace.Trace.SetAndTraceTransfer(this.ChannelExtension.ActivityID, true); 274 return new ProcessMessagesAsyncResult<TContract>(message, this, this.ChannelExtension.OperationTimeout, callback, state); 275 } 276 catch (Exception exception) 277 { 278 if (TD.RoutingServiceProcessingFailureIsEnabled()) 279 { 280 TD.RoutingServiceProcessingFailure(this.eventTraceActivity, OperationContext.Current.Channel.LocalAddress.ToString(), exception); 281 } 282 throw; 283 } 284 } 285 EndProcessMessage(IAsyncResult result)286 void EndProcessMessage<TContract>(IAsyncResult result) 287 { 288 try 289 { 290 FxTrace.Trace.SetAndTraceTransfer(this.ChannelExtension.ActivityID, true); 291 ProcessMessagesAsyncResult<TContract>.End(result); 292 } 293 catch (Exception exception) 294 { 295 if (TD.RoutingServiceProcessingFailureIsEnabled()) 296 { 297 TD.RoutingServiceProcessingFailure(this.eventTraceActivity, OperationContext.Current.Channel.LocalAddress.ToString(), exception); 298 } 299 throw; 300 } 301 } 302 BeginProcessRequest(Message message, AsyncCallback callback, object state)303 IAsyncResult BeginProcessRequest<TContract>(Message message, AsyncCallback callback, object state) 304 { 305 try 306 { 307 FxTrace.Trace.SetAndTraceTransfer(this.ChannelExtension.ActivityID, true); 308 return new ProcessRequestAsyncResult<TContract>(this, message, callback, state); 309 } 310 catch (Exception exception) 311 { 312 if (TD.RoutingServiceProcessingFailureIsEnabled()) 313 { 314 TD.RoutingServiceProcessingFailure(this.eventTraceActivity, OperationContext.Current.Channel.LocalAddress.ToString(), exception); 315 } 316 throw; 317 } 318 } 319 EndProcessRequest(IAsyncResult result)320 Message EndProcessRequest<TContract>(IAsyncResult result) 321 { 322 try 323 { 324 FxTrace.Trace.SetAndTraceTransfer(this.ChannelExtension.ActivityID, true); 325 return ProcessRequestAsyncResult<TContract>.End(result); 326 } 327 catch (Exception exception) 328 { 329 if (TD.RoutingServiceProcessingFailureIsEnabled()) 330 { 331 TD.RoutingServiceProcessingFailure(this.eventTraceActivity, OperationContext.Current.Channel.LocalAddress.ToString(), exception); 332 } 333 throw; 334 } 335 } 336 } 337 } 338