WsatProxy.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK