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