File: System\ServiceModel\Transactions\OletxTransactionHeader.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
    using System;
    using System.Diagnostics;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Transactions;
    using System.Xml;
 
    using Microsoft.Transactions.Wsat.Messaging;
 
    class OleTxTransactionHeader : MessageHeader
    {
        const string OleTxHeaderElement = OleTxTransactionExternalStrings.OleTxTransaction;
        const string OleTxNamespace = OleTxTransactionExternalStrings.Namespace;
        static readonly XmlDictionaryString CoordinationNamespace = XD.CoordinationExternal10Dictionary.Namespace; // we keep using wscoor10 namespace for compatibility
        
        byte[] propagationToken;
        WsatExtendedInformation wsatInfo;
 
        public OleTxTransactionHeader(byte[] propagationToken, WsatExtendedInformation wsatInfo)
        {
            this.propagationToken = propagationToken;
            this.wsatInfo = wsatInfo;
        }
 
        public override bool MustUnderstand
        {
            get { return true; }
        }
        
        public override string Name
        {
            get { return OleTxHeaderElement; }
        }
 
        public override string Namespace
        {
            get { return OleTxNamespace; }
        }
 
        public byte[] PropagationToken
        {
            get { return this.propagationToken; }
        }
 
        public WsatExtendedInformation WsatExtendedInformation
        {
            get { return this.wsatInfo; }
        }
 
        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
        {
            if (this.wsatInfo != null)
            {
                if (this.wsatInfo.Timeout != 0)
                {
                    writer.WriteAttributeString(XD.CoordinationExternalDictionary.Expires,
                                                CoordinationNamespace,
                                                XmlConvert.ToString(this.wsatInfo.Timeout));
                }
 
                if (!string.IsNullOrEmpty(this.wsatInfo.Identifier))
                {
                    writer.WriteAttributeString(XD.CoordinationExternalDictionary.Identifier,
                                                CoordinationNamespace,
                                                this.wsatInfo.Identifier);
                }
            }
 
            WritePropagationTokenElement(writer, this.propagationToken);
        }
 
        public static OleTxTransactionHeader ReadFrom(Message message)
        {
            int index;
            try
            {
                index = message.Headers.FindHeader(OleTxHeaderElement, OleTxNamespace);
            }
            catch (MessageHeaderException e)
            {
                DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TransactionException(SR.GetString(SR.OleTxHeaderCorrupt), e));
            }
 
            if (index < 0)
                return null;
 
            OleTxTransactionHeader oleTxHeader;
            XmlDictionaryReader reader = message.Headers.GetReaderAtHeader(index);
            using (reader)
            {
                try
                {
                    oleTxHeader = ReadFrom(reader);
                }
                catch (XmlException xe)
                {
                    DiagnosticUtility.TraceHandledException(xe, TraceEventType.Error);
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TransactionException(SR.GetString(SR.OleTxHeaderCorrupt), xe));
                }
            }
 
            MessageHeaderInfo header = message.Headers[index];
            if (!message.Headers.UnderstoodHeaders.Contains(header))
            {
                message.Headers.UnderstoodHeaders.Add(header);
            }
 
            return oleTxHeader;
        }
 
        static OleTxTransactionHeader ReadFrom(XmlDictionaryReader reader)
        {
            WsatExtendedInformation info = null;
 
            if (reader.IsStartElement(XD.OleTxTransactionExternalDictionary.OleTxTransaction,
                                      XD.OleTxTransactionExternalDictionary.Namespace))
            {
                string identifier = reader.GetAttribute(XD.CoordinationExternalDictionary.Identifier, CoordinationNamespace);
 
                if (!string.IsNullOrEmpty(identifier))
                {
                    // Verify identifier is really a URI
                    Uri uri;
                    if (!Uri.TryCreate(identifier, UriKind.Absolute, out uri))
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidWsatExtendedInfo)));
                    }
                }
 
                string attr = reader.GetAttribute(XD.CoordinationExternalDictionary.Expires, CoordinationNamespace);
 
                uint timeout = 0;
                if (!string.IsNullOrEmpty(attr))
                {
                    try
                    {
                        timeout = XmlConvert.ToUInt32(attr);
                    }
                    catch (FormatException e)
                    {
                        DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidWsatExtendedInfo), e));
                    }
                    catch (OverflowException e)
                    {
                        DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidWsatExtendedInfo), e));
                    }
                }
 
                if (!string.IsNullOrEmpty(identifier) || timeout != 0)
                {
                    info = new WsatExtendedInformation(identifier, timeout);
                }
            }
 
            reader.ReadFullStartElement(XD.OleTxTransactionExternalDictionary.OleTxTransaction,
                                        XD.OleTxTransactionExternalDictionary.Namespace);
 
            byte[] propagationToken = ReadPropagationTokenElement(reader);
 
            // Skip extensibility elements...
            while (reader.IsStartElement())
            {
                reader.Skip();
            }
            reader.ReadEndElement();
 
            return new OleTxTransactionHeader(propagationToken, info);
        }
 
        public static void WritePropagationTokenElement(XmlDictionaryWriter writer, byte[] propagationToken)
        {
            writer.WriteStartElement(XD.OleTxTransactionExternalDictionary.PropagationToken,
                                     XD.OleTxTransactionExternalDictionary.Namespace);
            writer.WriteBase64(propagationToken, 0, propagationToken.Length);
            writer.WriteEndElement();
        }
 
        public static bool IsStartPropagationTokenElement(XmlDictionaryReader reader)
        {
            return reader.IsStartElement(XD.OleTxTransactionExternalDictionary.PropagationToken,
                                         XD.OleTxTransactionExternalDictionary.Namespace);
        }
 
        public static byte[] ReadPropagationTokenElement(XmlDictionaryReader reader)
        {
            reader.ReadFullStartElement(XD.OleTxTransactionExternalDictionary.PropagationToken,
                                        XD.OleTxTransactionExternalDictionary.Namespace);
 
            byte[] propagationToken = reader.ReadContentAsBase64();
            if (propagationToken.Length == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidPropagationToken)));
            }
 
            reader.ReadEndElement();
 
            return propagationToken;
        }
    }
}