Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Transactions / WsatProxy.cs / 1 / WsatProxy.cs
//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------- namespace System.ServiceModel.Transactions { using System; using System.ServiceModel.Channels; using System.Diagnostics; using System.Runtime.InteropServices; using System.ServiceModel; using System.Text; using System.Threading; using System.Transactions; using System.ServiceModel.Security; using System.ServiceModel.Diagnostics; using Microsoft.Transactions.Bridge; using Microsoft.Transactions.Wsat.Messaging; using Microsoft.Transactions.Wsat.Protocol; using DiagnosticUtility = System.ServiceModel.DiagnosticUtility; class WsatProxy { WsatConfiguration wsatConfig; ProtocolVersion protocolVersion; CoordinationService coordinationService; ActivationProxy activationProxy; object proxyLock = new object(); public WsatProxy(WsatConfiguration wsatConfig, ProtocolVersion protocolVersion) { this.wsatConfig = wsatConfig; this.protocolVersion = protocolVersion; } //============================================================================================= public Transaction UnmarshalTransaction(WsatTransactionInfo info) { if(info.Context.ProtocolVersion != this.protocolVersion) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion))); } if (wsatConfig.OleTxUpgradeEnabled) { byte[] propToken = info.Context.PropagationToken; if (propToken != null) { try { return OleTxTransactionInfo.UnmarshalPropagationToken(propToken); } catch (TransactionException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning); } // Fall back to WS-AT unmarshal if (DiagnosticUtility.ShouldTraceInformation) DiagnosticUtility.DiagnosticTrace.TraceEvent(TraceEventType.Information, TraceCode.TxFailedToNegotiateOleTx, SR.GetString(SR.TraceCodeTxFailedToNegotiateOleTx, info.Context.Identifier)); } } // Optimization: if the context's registration service points to our local TM, we can // skip the CreateCoordinationContext step CoordinationContext localContext = info.Context; if (!this.wsatConfig.IsLocalRegistrationService(localContext.RegistrationService, this.protocolVersion)) { // Our WS-AT protocol service for the context's protocol version should be enabled if (!this.wsatConfig.IsProtocolServiceEnabled(this.protocolVersion)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionException(SR.GetString(SR.WsatProtocolServiceDisabled, this.protocolVersion))); } // We should have enabled inbound transactions if (!this.wsatConfig.InboundEnabled) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionException(SR.GetString(SR.InboundTransactionsDisabled))); } // The sender should have enabled both WS-AT and outbound transactions if (this.wsatConfig.IsDisabledRegistrationService(localContext.RegistrationService)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionException(SR.GetString(SR.SourceTransactionsDisabled))); } // Ask the WS-AT protocol service to unmarshal the transaction localContext = CreateCoordinationContext(info); } Guid transactionId = localContext.LocalTransactionId; if (transactionId == Guid.Empty) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionException(SR.GetString(SR.InvalidCoordinationContextTransactionId))); } byte[] propagationToken = MarshalPropagationToken(ref transactionId, localContext.IsolationLevel, localContext.IsolationFlags, localContext.Description); return OleTxTransactionInfo.UnmarshalPropagationToken(propagationToken); } //============================================================================================= CoordinationContext CreateCoordinationContext(WsatTransactionInfo info) { CreateCoordinationContext cccMessage = new CreateCoordinationContext(this.protocolVersion); cccMessage.CurrentContext = info.Context; cccMessage.IssuedToken = info.IssuedToken; try { // This was necessary during some portions of WCF 1.0 development // It is probably not needed now. However, it seems conceptually // solid to separate this operation from the incoming app message as // much as possible. There have also been enough ServiceModel bugs in // this area that it does not seem wise to remove this at the moment // (2006/3/30, WCF 1.0 RC1 milestone) using (new OperationContextScope((OperationContext)null)) { return Enlist(ref cccMessage).CoordinationContext; } } catch (WsatFaultException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Error); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionException(SR.GetString(SR.UnmarshalTransactionFaulted, e.Message), e)); } catch (WsatSendFailureException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Error); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionManagerCommunicationException(SR.GetString(SR.TMCommunicationError), e)); } } //============================================================================================== CreateCoordinationContextResponse Enlist(ref CreateCoordinationContext cccMessage) { int attempts = 0; while (true) { ActivationProxy proxy = GetActivationProxy(); EndpointAddress address = proxy.To; EndpointAddress localActivationService = this.wsatConfig.LocalActivationService(this.protocolVersion); EndpointAddress remoteActivationService = this.wsatConfig.RemoteActivationService(this.protocolVersion); try { return proxy.SendCreateCoordinationContext(ref cccMessage); } catch (WsatSendFailureException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning); // Don't retry if we're not likely to succeed on the next pass Exception inner = e.InnerException; if (inner is TimeoutException || inner is QuotaExceededException || inner is FaultException) throw; // Give up after 10 attempts if (attempts > 10) throw; if (attempts > 5 && remoteActivationService != null && ReferenceEquals(address, localActivationService)) { // Switch over to the remote activation service. // In clustered scenarios this uses the cluster name, // so it should always work if the resource is online // This covers the case where we were using a local cluster // resource which failed over to another node address = remoteActivationService; } } finally { proxy.Release(); } TryStartMsdtcService(); // We need to refresh our proxy here because the channel is sessionful // and may simply decided to enter the faulted state if something fails. RefreshActivationProxy(address); // Don't spin Thread.Sleep(0); attempts++; } } //============================================================================================= void TryStartMsdtcService() { try { TransactionInterop.GetWhereabouts(); } catch (TransactionException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Warning); } } //============================================================================================== ActivationProxy GetActivationProxy() { if (this.activationProxy == null) { RefreshActivationProxy(null); } lock (this.proxyLock) { ActivationProxy proxy = this.activationProxy; proxy.AddRef(); return proxy; } } //============================================================================================== void RefreshActivationProxy(EndpointAddress suggestedAddress) { // Pick an address in the following order... EndpointAddress address = suggestedAddress; if (address == null) { address = this.wsatConfig.LocalActivationService(this.protocolVersion); if (address == null) { address = this.wsatConfig.RemoteActivationService(this.protocolVersion); } } if (!(address != null)) { // tx processing requires failfast when state is inconsistent DiagnosticUtility.FailFast("Must have valid activation service address"); } lock (this.proxyLock) { ActivationProxy newProxy = CreateActivationProxy(address); if (this.activationProxy != null) this.activationProxy.Release(); this.activationProxy = newProxy; } } //============================================================================================= ActivationProxy CreateActivationProxy(EndpointAddress address) { CoordinationService coordination = GetCoordinationService(); try { return coordination.CreateActivationProxy(address, false); } catch (CreateChannelFailureException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Error); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionException(SR.GetString(SR.WsatProxyCreationFailed), e)); } } //============================================================================================== CoordinationService GetCoordinationService() { if (this.coordinationService == null) { lock (this.proxyLock) { if (this.coordinationService == null) { try { CoordinationServiceConfiguration config = new CoordinationServiceConfiguration(); config.Mode = CoordinationServiceMode.Formatter; config.RemoteClientsEnabled = this.wsatConfig.RemoteActivationService(this.protocolVersion) != null; this.coordinationService = new CoordinationService(config, this.protocolVersion); } catch (MessagingInitializationException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Error); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new TransactionException(SR.GetString(SR.WsatMessagingInitializationFailed), e)); } } } } return this.coordinationService; } //------------------------------------------------------------------------------- // Marshal/Unmarshaling related stuff //------------------------------------------------------------------------------- // Keep a propagation token around as a template for hydrating transactions static byte[] fixedPropagationToken; static byte[] CreateFixedPropagationToken() { if (fixedPropagationToken == null) { CommittableTransaction tx = new CommittableTransaction(); byte[] token = TransactionInterop.GetTransmitterPropagationToken(tx); // Don't abort the transaction. People notice this and do not like it. try { tx.Commit(); } catch (TransactionException e) { DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); } Interlocked.CompareExchange(ref fixedPropagationToken, token, null); } byte[] tokenCopy = new byte[fixedPropagationToken.Length]; Array.Copy(fixedPropagationToken, tokenCopy, fixedPropagationToken.Length); return tokenCopy; } // This is what a propagation token looks like: // // struct PropagationToken // { // DWORD dwVersionMin; // DWORD dwVersionMax; // GUID guidTx; // ISOLATIONLEVEL isoLevel; // ISOFLAG isoFlags; // ULONG cbSourceTmAddr; // char szDesc[40]; // [etc] // } static byte[] MarshalPropagationToken(ref Guid transactionId, IsolationLevel isoLevel, IsolationFlags isoFlags, string description) { const int offsetof_guidTx = 8; const int offsetof_isoLevel = 24; const int offsetof_isoFlags = 28; const int offsetof_szDesc = 36; const int MaxDescriptionLength = 39; byte[] token = CreateFixedPropagationToken(); // Replace transaction id byte[] transactionIdBytes = transactionId.ToByteArray(); Array.Copy(transactionIdBytes, 0, token, offsetof_guidTx, transactionIdBytes.Length); // Replace isolation level byte[] isoLevelBytes = BitConverter.GetBytes((int) ConvertIsolationLevel(isoLevel)); Array.Copy(isoLevelBytes, 0, token, offsetof_isoLevel, isoLevelBytes.Length); // Replace isolation flags byte[] isoFlagsBytes = BitConverter.GetBytes((int) isoFlags); Array.Copy(isoFlagsBytes, 0, token, offsetof_isoFlags, isoFlagsBytes.Length); // Replace description if (!string.IsNullOrEmpty(description)) { byte[] descriptionBytes = Encoding.UTF8.GetBytes(description); int copyDescriptionBytes = Math.Min(descriptionBytes.Length, MaxDescriptionLength); Array.Copy(descriptionBytes, 0, token, offsetof_szDesc, copyDescriptionBytes); token[offsetof_szDesc + copyDescriptionBytes] = 0; } return token; } enum ProxyIsolationLevel : int { Unspecified = -1, Chaos = 0x10, ReadUncommitted = 0x100, Browse = 0x100, CursorStability = 0x1000, ReadCommitted = 0x1000, RepeatableRead = 0x10000, Serializable = 0x100000, Isolated = 0x100000 } static ProxyIsolationLevel ConvertIsolationLevel(IsolationLevel IsolationLevel) { ProxyIsolationLevel retVal; switch (IsolationLevel) { case IsolationLevel.Serializable: retVal = ProxyIsolationLevel.Serializable; break; case IsolationLevel.RepeatableRead: retVal = ProxyIsolationLevel.RepeatableRead; break; case IsolationLevel.ReadCommitted: retVal = ProxyIsolationLevel.ReadCommitted; break; case IsolationLevel.ReadUncommitted: retVal = ProxyIsolationLevel.ReadUncommitted; break; case IsolationLevel.Unspecified: retVal = ProxyIsolationLevel.Unspecified; break; default: retVal = ProxyIsolationLevel.Serializable; break; } return retVal; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ContractMapping.cs
- DockPanel.cs
- ValidatingPropertiesEventArgs.cs
- FormsIdentity.cs
- BitmapEffectInput.cs
- DebugHandleTracker.cs
- EnumValidator.cs
- HttpStreams.cs
- Utils.cs
- HtmlSelect.cs
- _NetRes.cs
- SettingsBase.cs
- HttpRuntimeSection.cs
- EdmRelationshipNavigationPropertyAttribute.cs
- UserControl.cs
- MSHTMLHostUtil.cs
- ByteAnimationBase.cs
- PrimaryKeyTypeConverter.cs
- StylusPointPropertyInfo.cs
- LineGeometry.cs
- ProfilePropertySettings.cs
- BrowserCapabilitiesCodeGenerator.cs
- MediaCommands.cs
- ReturnValue.cs
- WebConfigurationManager.cs
- XmlDocumentFragment.cs
- FrameworkContextData.cs
- PlainXmlDeserializer.cs
- RegexFCD.cs
- FontFamilyValueSerializer.cs
- TableLayoutPanel.cs
- sqlpipe.cs
- MemberMemberBinding.cs
- PtsHelper.cs
- FileCodeGroup.cs
- DataBoundControlHelper.cs
- DocumentPageHost.cs
- InputDevice.cs
- GlobalEventManager.cs
- MimeTypeAttribute.cs
- ElementMarkupObject.cs
- LayoutEvent.cs
- PropertyEmitter.cs
- PointLight.cs
- BitmapFrameEncode.cs
- Number.cs
- DependencyPropertyChangedEventArgs.cs
- DatatypeImplementation.cs
- Main.cs
- NamespaceInfo.cs
- QilInvoke.cs
- TableMethodGenerator.cs
- DBDataPermissionAttribute.cs
- QueryConverter.cs
- SoapAttributes.cs
- TypeDescriptor.cs
- ContentType.cs
- cookiecontainer.cs
- UriTemplateEquivalenceComparer.cs
- ButtonChrome.cs
- XslException.cs
- CompressStream.cs
- ConversionContext.cs
- ItemCheckEvent.cs
- _BufferOffsetSize.cs
- ClientFormsIdentity.cs
- InfoCardBaseException.cs
- RoutedCommand.cs
- X509ChainElement.cs
- webbrowsersite.cs
- DeviceFilterDictionary.cs
- GridViewSelectEventArgs.cs
- EntityContainerAssociationSetEnd.cs
- wmiprovider.cs
- XmlILModule.cs
- Peer.cs
- NoneExcludedImageIndexConverter.cs
- MachinePropertyVariants.cs
- XmlIlTypeHelper.cs
- ObjectQuery_EntitySqlExtensions.cs
- New.cs
- FlowDocumentFormatter.cs
- XmlSignificantWhitespace.cs
- InternalBufferOverflowException.cs
- DebugController.cs
- ServiceDescription.cs
- XhtmlTextWriter.cs
- SystemTcpStatistics.cs
- ChangeDirector.cs
- Closure.cs
- ElementHostPropertyMap.cs
- TargetControlTypeAttribute.cs
- NumberSubstitution.cs
- DrawListViewSubItemEventArgs.cs
- WSHttpBindingBase.cs
- EventLogger.cs
- FormViewUpdateEventArgs.cs
- LoadWorkflowByInstanceKeyCommand.cs
- login.cs
- TableLayoutPanelCellPosition.cs