1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 namespace System.ServiceModel.Transactions
5 {
6     using System;
7     using System.Diagnostics;
8     using System.ServiceModel;
9     using System.ServiceModel.Channels;
10     using System.Transactions;
11     using System.Xml;
12 
13     using Microsoft.Transactions.Wsat.Messaging;
14 
15     class OleTxTransactionHeader : MessageHeader
16     {
17         const string OleTxHeaderElement = OleTxTransactionExternalStrings.OleTxTransaction;
18         const string OleTxNamespace = OleTxTransactionExternalStrings.Namespace;
19         static readonly XmlDictionaryString CoordinationNamespace = XD.CoordinationExternal10Dictionary.Namespace; // we keep using wscoor10 namespace for compatibility
20 
21         byte[] propagationToken;
22         WsatExtendedInformation wsatInfo;
23 
OleTxTransactionHeader(byte[] propagationToken, WsatExtendedInformation wsatInfo)24         public OleTxTransactionHeader(byte[] propagationToken, WsatExtendedInformation wsatInfo)
25         {
26             this.propagationToken = propagationToken;
27             this.wsatInfo = wsatInfo;
28         }
29 
30         public override bool MustUnderstand
31         {
32             get { return true; }
33         }
34 
35         public override string Name
36         {
37             get { return OleTxHeaderElement; }
38         }
39 
40         public override string Namespace
41         {
42             get { return OleTxNamespace; }
43         }
44 
45         public byte[] PropagationToken
46         {
47             get { return this.propagationToken; }
48         }
49 
50         public WsatExtendedInformation WsatExtendedInformation
51         {
52             get { return this.wsatInfo; }
53         }
54 
OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)55         protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
56         {
57             if (this.wsatInfo != null)
58             {
59                 if (this.wsatInfo.Timeout != 0)
60                 {
61                     writer.WriteAttributeString(XD.CoordinationExternalDictionary.Expires,
62                                                 CoordinationNamespace,
63                                                 XmlConvert.ToString(this.wsatInfo.Timeout));
64                 }
65 
66                 if (!string.IsNullOrEmpty(this.wsatInfo.Identifier))
67                 {
68                     writer.WriteAttributeString(XD.CoordinationExternalDictionary.Identifier,
69                                                 CoordinationNamespace,
70                                                 this.wsatInfo.Identifier);
71                 }
72             }
73 
74             WritePropagationTokenElement(writer, this.propagationToken);
75         }
76 
ReadFrom(Message message)77         public static OleTxTransactionHeader ReadFrom(Message message)
78         {
79             int index;
80             try
81             {
82                 index = message.Headers.FindHeader(OleTxHeaderElement, OleTxNamespace);
83             }
84             catch (MessageHeaderException e)
85             {
86                 DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
87                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TransactionException(SR.GetString(SR.OleTxHeaderCorrupt), e));
88             }
89 
90             if (index < 0)
91                 return null;
92 
93             OleTxTransactionHeader oleTxHeader;
94             XmlDictionaryReader reader = message.Headers.GetReaderAtHeader(index);
95             using (reader)
96             {
97                 try
98                 {
99                     oleTxHeader = ReadFrom(reader);
100                 }
101                 catch (XmlException xe)
102                 {
103                     DiagnosticUtility.TraceHandledException(xe, TraceEventType.Error);
104                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TransactionException(SR.GetString(SR.OleTxHeaderCorrupt), xe));
105                 }
106             }
107 
108             MessageHeaderInfo header = message.Headers[index];
109             if (!message.Headers.UnderstoodHeaders.Contains(header))
110             {
111                 message.Headers.UnderstoodHeaders.Add(header);
112             }
113 
114             return oleTxHeader;
115         }
116 
ReadFrom(XmlDictionaryReader reader)117         static OleTxTransactionHeader ReadFrom(XmlDictionaryReader reader)
118         {
119             WsatExtendedInformation info = null;
120 
121             if (reader.IsStartElement(XD.OleTxTransactionExternalDictionary.OleTxTransaction,
122                                       XD.OleTxTransactionExternalDictionary.Namespace))
123             {
124                 string identifier = reader.GetAttribute(XD.CoordinationExternalDictionary.Identifier, CoordinationNamespace);
125 
126                 if (!string.IsNullOrEmpty(identifier))
127                 {
128                     // Verify identifier is really a URI
129                     Uri uri;
130                     if (!Uri.TryCreate(identifier, UriKind.Absolute, out uri))
131                     {
132                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidWsatExtendedInfo)));
133                     }
134                 }
135 
136                 string attr = reader.GetAttribute(XD.CoordinationExternalDictionary.Expires, CoordinationNamespace);
137 
138                 uint timeout = 0;
139                 if (!string.IsNullOrEmpty(attr))
140                 {
141                     try
142                     {
143                         timeout = XmlConvert.ToUInt32(attr);
144                     }
145                     catch (FormatException e)
146                     {
147                         DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
148                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidWsatExtendedInfo), e));
149                     }
150                     catch (OverflowException e)
151                     {
152                         DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
153                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidWsatExtendedInfo), e));
154                     }
155                 }
156 
157                 if (!string.IsNullOrEmpty(identifier) || timeout != 0)
158                 {
159                     info = new WsatExtendedInformation(identifier, timeout);
160                 }
161             }
162 
163             reader.ReadFullStartElement(XD.OleTxTransactionExternalDictionary.OleTxTransaction,
164                                         XD.OleTxTransactionExternalDictionary.Namespace);
165 
166             byte[] propagationToken = ReadPropagationTokenElement(reader);
167 
168             // Skip extensibility elements...
169             while (reader.IsStartElement())
170             {
171                 reader.Skip();
172             }
173             reader.ReadEndElement();
174 
175             return new OleTxTransactionHeader(propagationToken, info);
176         }
177 
WritePropagationTokenElement(XmlDictionaryWriter writer, byte[] propagationToken)178         public static void WritePropagationTokenElement(XmlDictionaryWriter writer, byte[] propagationToken)
179         {
180             writer.WriteStartElement(XD.OleTxTransactionExternalDictionary.PropagationToken,
181                                      XD.OleTxTransactionExternalDictionary.Namespace);
182             writer.WriteBase64(propagationToken, 0, propagationToken.Length);
183             writer.WriteEndElement();
184         }
185 
IsStartPropagationTokenElement(XmlDictionaryReader reader)186         public static bool IsStartPropagationTokenElement(XmlDictionaryReader reader)
187         {
188             return reader.IsStartElement(XD.OleTxTransactionExternalDictionary.PropagationToken,
189                                          XD.OleTxTransactionExternalDictionary.Namespace);
190         }
191 
ReadPropagationTokenElement(XmlDictionaryReader reader)192         public static byte[] ReadPropagationTokenElement(XmlDictionaryReader reader)
193         {
194             reader.ReadFullStartElement(XD.OleTxTransactionExternalDictionary.PropagationToken,
195                                         XD.OleTxTransactionExternalDictionary.Namespace);
196 
197             byte[] propagationToken = reader.ReadContentAsBase64();
198             if (propagationToken.Length == 0)
199             {
200                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.InvalidPropagationToken)));
201             }
202 
203             reader.ReadEndElement();
204 
205             return propagationToken;
206         }
207     }
208 }
209