1 //----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Collections.Generic;
7     using System.ServiceModel.Description;
8     using System.Diagnostics;
9     using System.ServiceModel;
10     using System.ServiceModel.Security;
11 
12     using System.Transactions;
13     using System.ServiceModel.Transactions;
14     using System.Runtime.CompilerServices;
15     using System.Runtime.Remoting;
16     using System.Runtime.Remoting.Messaging;
17     using SR = System.ServiceModel.SR;
18     using System.ServiceModel.Diagnostics;
19 
20     internal interface ITransactionChannel
21     {
22         // These get run on forward-going messages only
WriteTransactionDataToMessage(Message message, MessageDirection direction)23         void WriteTransactionDataToMessage(Message message, MessageDirection direction);
ReadTransactionDataFromMessage(Message message, MessageDirection direction)24         void ReadTransactionDataFromMessage(Message message, MessageDirection direction);
25         // These get run in both directions (request and reply).  If other flowable-things are added
26         // that need to flow both ways, these methods should be renamed and generalized to do it
ReadIssuedTokens(Message message, MessageDirection direction)27         void ReadIssuedTokens(Message message, MessageDirection direction);
WriteIssuedTokens(Message message, MessageDirection direction)28         void WriteIssuedTokens(Message message, MessageDirection direction);
29     }
30 
31     abstract class TransactionChannel<TChannel>
32         : LayeredChannel<TChannel>, ITransactionChannel
33         where TChannel : class, IChannel
34     {
35         ITransactionChannelManager factory;
36         TransactionFormatter formatter;
37 
TransactionChannel(ChannelManagerBase channelManager, TChannel innerChannel)38         protected TransactionChannel(ChannelManagerBase channelManager, TChannel innerChannel)
39             : base(channelManager, innerChannel)
40         {
41             this.factory = (ITransactionChannelManager)channelManager;
42 
43             if (this.factory.TransactionProtocol == TransactionProtocol.OleTransactions)
44             {
45                 this.formatter = TransactionFormatter.OleTxFormatter;
46             }
47             else if (this.factory.TransactionProtocol == TransactionProtocol.WSAtomicTransactionOctober2004)
48             {
49                 this.formatter = TransactionFormatter.WsatFormatter10;
50             }
51             else if (this.factory.TransactionProtocol == TransactionProtocol.WSAtomicTransaction11)
52             {
53                 this.formatter = TransactionFormatter.WsatFormatter11;
54             }
55             else
56             {
57                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
58                     new ArgumentException(SR.GetString(SR.SFxBadTransactionProtocols)));
59             }
60         }
61 
62         internal TransactionFormatter Formatter
63         {
64             get
65             {
66                 return this.formatter;
67             }
68         }
69 
70         internal TransactionProtocol Protocol
71         {
72             get
73             {
74                 return this.factory.TransactionProtocol;
75             }
76         }
77 
GetProperty()78         public override T GetProperty<T>()
79         {
80             if (typeof(T) == typeof(FaultConverter))
81             {
82                 return (T)(object)new TransactionChannelFaultConverter<TChannel>(this);
83             }
84 
85             return base.GetProperty<T>();
86         }
87 
88         public T GetInnerProperty<T>() where T : class
89         {
90             return base.InnerChannel.GetProperty<T>();
91         }
92 
Found(int index)93         static bool Found(int index)
94         {
95             return index != -1;
96         }
97 
FaultOnMessage(Message message, string reason, string codeString)98         void FaultOnMessage(Message message, string reason, string codeString)
99         {
100             FaultCode code = FaultCode.CreateSenderFaultCode(codeString, FaultCodeConstants.Namespaces.Transactions);
101             FaultException fault = new FaultException(reason, code, FaultCodeConstants.Actions.Transactions);
102             throw TraceUtility.ThrowHelperError(fault, message);
103         }
104 
GetIssuedTokens(Message message)105         ICollection<RequestSecurityTokenResponse> GetIssuedTokens(Message message)
106         {
107             return IssuedTokensHeader.ExtractIssuances(message, this.factory.StandardsManager, message.Version.Envelope.UltimateDestinationActorValues, null);
108         }
109 
ReadIssuedTokens(Message message, MessageDirection direction)110         public void ReadIssuedTokens(Message message, MessageDirection direction)
111         {
112             TransactionFlowOption option = this.factory.FlowIssuedTokens;
113 
114             ICollection<RequestSecurityTokenResponse> issuances = this.GetIssuedTokens(message);
115 
116             if (issuances != null && issuances.Count != 0)
117             {
118                 if (option == TransactionFlowOption.NotAllowed)
119                 {
120                     FaultOnMessage(message, SR.GetString(SR.IssuedTokenFlowNotAllowed), FaultCodeConstants.Codes.IssuedTokenFlowNotAllowed);
121                 }
122 
123                 foreach (RequestSecurityTokenResponse rstr in issuances)
124                 {
125                     TransactionFlowProperty.Ensure(message).IssuedTokens.Add(rstr);
126                 }
127             }
128         }
129 
ReadTransactionFromMessage(Message message, TransactionFlowOption txFlowOption)130         void ReadTransactionFromMessage(Message message, TransactionFlowOption txFlowOption)
131         {
132             TransactionInfo transactionInfo = null;
133             try
134             {
135                 transactionInfo = this.formatter.ReadTransaction(message);
136             }
137             catch (TransactionException e)
138             {
139                 DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
140                 FaultOnMessage(message, SR.GetString(SR.SFxTransactionDeserializationFailed, e.Message), FaultCodeConstants.Codes.TransactionHeaderMalformed);
141             }
142 
143             if (transactionInfo != null)
144             {
145                 TransactionMessageProperty.Set(transactionInfo, message);
146             }
147             else if (txFlowOption == TransactionFlowOption.Mandatory)
148             {
149                 FaultOnMessage(message, SR.GetString(SR.SFxTransactionFlowRequired), FaultCodeConstants.Codes.TransactionHeaderMissing);
150             }
151         }
152 
ReadTransactionDataFromMessage(Message message, MessageDirection direction)153         public virtual void ReadTransactionDataFromMessage(Message message, MessageDirection direction)
154         {
155             this.ReadIssuedTokens(message, direction);
156 
157             TransactionFlowOption txFlowOption = this.factory.GetTransaction(direction, message.Headers.Action);
158             if (TransactionFlowOptionHelper.AllowedOrRequired(txFlowOption))
159             {
160                 this.ReadTransactionFromMessage(message, txFlowOption);
161             }
162         }
163 
WriteTransactionDataToMessage(Message message, MessageDirection direction)164         public void WriteTransactionDataToMessage(Message message, MessageDirection direction)
165         {
166             TransactionFlowOption txFlowOption = this.factory.GetTransaction(direction, message.Headers.Action);
167             if (TransactionFlowOptionHelper.AllowedOrRequired(txFlowOption))
168             {
169                 this.WriteTransactionToMessage(message, txFlowOption);
170             }
171 
172             if (TransactionFlowOptionHelper.AllowedOrRequired(this.factory.FlowIssuedTokens))
173             {
174                 this.WriteIssuedTokens(message, direction);
175             }
176 
177         }
178 
179         [MethodImpl(MethodImplOptions.NoInlining)]
WriteTransactionToMessage(Message message, TransactionFlowOption txFlowOption)180         void WriteTransactionToMessage(Message message, TransactionFlowOption txFlowOption)
181         {
182             Transaction transaction = TransactionFlowProperty.TryGetTransaction(message);
183 
184             if (transaction != null)
185             {
186                 try
187                 {
188                     this.formatter.WriteTransaction(transaction, message);
189                 }
190                 catch (TransactionException e)
191                 {
192                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(e.Message, e));
193                 }
194             }
195             else if (txFlowOption == TransactionFlowOption.Mandatory)
196             {
197                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(SR.GetString(SR.SFxTransactionFlowRequired)));
198             }
199         }
200 
WriteIssuedTokens(Message message, MessageDirection direction)201         public void WriteIssuedTokens(Message message, MessageDirection direction)
202         {
203             ICollection<RequestSecurityTokenResponse> issuances = TransactionFlowProperty.TryGetIssuedTokens(message);
204             if (issuances != null)
205             {
206                 IssuedTokensHeader header = new IssuedTokensHeader(issuances, this.factory.StandardsManager);
207                 message.Headers.Add(header);
208 
209             }
210         }
211     }
212 }
213