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
- ExceptQueryOperator.cs
- TcpConnectionPool.cs
- Connector.cs
- MarshalDirectiveException.cs
- StyleBamlTreeBuilder.cs
- ApplicationBuildProvider.cs
- CompareValidator.cs
- SoapAttributes.cs
- Ref.cs
- MarkerProperties.cs
- DeclarativeCatalogPartDesigner.cs
- DictionaryContent.cs
- XmlReflectionImporter.cs
- ToolStripDropDownClosedEventArgs.cs
- RedistVersionInfo.cs
- HtmlLinkAdapter.cs
- DataGridViewCellValidatingEventArgs.cs
- COM2IDispatchConverter.cs
- OpenTypeCommon.cs
- FlowDocumentView.cs
- PropVariant.cs
- FreezableDefaultValueFactory.cs
- ConversionValidationRule.cs
- FolderLevelBuildProviderAppliesToAttribute.cs
- HideDisabledControlAdapter.cs
- SmtpFailedRecipientException.cs
- ArrayExtension.cs
- SharedStatics.cs
- XmlSchemaSimpleType.cs
- Thumb.cs
- OrderedHashRepartitionStream.cs
- ReferentialConstraint.cs
- ParseChildrenAsPropertiesAttribute.cs
- base64Transforms.cs
- MenuItem.cs
- DrawListViewColumnHeaderEventArgs.cs
- GlyphRun.cs
- TypeSystemProvider.cs
- NullExtension.cs
- EventLogSession.cs
- ConfigurationElement.cs
- ConfigXmlText.cs
- DrawListViewColumnHeaderEventArgs.cs
- SelectedCellsCollection.cs
- TransportContext.cs
- FileSecurity.cs
- UserValidatedEventArgs.cs
- SmtpDateTime.cs
- TemplateXamlParser.cs
- SafeSystemMetrics.cs
- CounterCreationDataCollection.cs
- MasterPage.cs
- AssociationSetEnd.cs
- StringArrayConverter.cs
- MailWebEventProvider.cs
- ComplexTypeEmitter.cs
- ZipArchive.cs
- Composition.cs
- TriState.cs
- LicenseException.cs
- BrowserCapabilitiesFactory.cs
- DispatcherObject.cs
- RoutedEvent.cs
- DbConnectionPoolCounters.cs
- StylusDownEventArgs.cs
- ReadOnlyPropertyMetadata.cs
- AnimatedTypeHelpers.cs
- Stackframe.cs
- SocketAddress.cs
- SqlDataSourceCommandEventArgs.cs
- BitmapScalingModeValidation.cs
- CommonRemoteMemoryBlock.cs
- WebPartEditVerb.cs
- KeyValuePair.cs
- GlyphManager.cs
- TypeReference.cs
- TypeNameHelper.cs
- ContainerUIElement3D.cs
- TransportListener.cs
- CollectionsUtil.cs
- PathSegmentCollection.cs
- ProtocolsConfiguration.cs
- SendReply.cs
- ColumnMapVisitor.cs
- EventsTab.cs
- CapabilitiesSection.cs
- ReadWriteSpinLock.cs
- EntityStoreSchemaFilterEntry.cs
- DecimalConverter.cs
- ApplicationException.cs
- SqlDataSourceQueryConverter.cs
- DefaultEvaluationContext.cs
- PersonalizationStateInfo.cs
- MailWriter.cs
- DbConnectionFactory.cs
- FastEncoder.cs
- WmpBitmapEncoder.cs
- SubtreeProcessor.cs
- GuidelineCollection.cs
- ExpandCollapsePattern.cs