| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Transactions
- {
- using System;
- using System.Runtime;
- using System.Security.Permissions;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Security;
- using System.Transactions;
- using System.Xml;
- using Microsoft.Transactions.Wsat.Messaging;
- using Microsoft.Transactions.Wsat.Protocol;
- using DiagnosticUtility = System.ServiceModel.DiagnosticUtility;
- abstract class WsatTransactionFormatter : TransactionFormatter
- {
- bool initialized;
- WsatConfiguration wsatConfig;
- WsatProxy wsatProxy;
- ProtocolVersion protocolVersion;
- protected WsatTransactionFormatter(ProtocolVersion protocolVersion)
- {
- this.protocolVersion = protocolVersion;
- }
- //=======================================================================================
- void EnsureInitialized()
- {
- if (!this.initialized)
- {
- lock (this)
- {
- if (!this.initialized)
- {
- this.wsatConfig = new WsatConfiguration();
- this.wsatProxy = new WsatProxy(this.wsatConfig, this.protocolVersion);
- this.initialized = true;
- }
- }
- }
- }
- //=======================================================================================
- // The demand is not added now (in 4.5), to avoid a breaking change. To be considered in the next version.
- /*
- [PermissionSet(SecurityAction.Demand, Unrestricted = true)] // because we call code from a non-APTCA assembly; WSATs are not supported in partial trust, so customers should not be broken by this demand
- */
- public override void WriteTransaction(Transaction transaction, Message message)
- {
- EnsureInitialized();
- ForcePromotion(transaction);
- // Make a context and add it to the message
- CoordinationContext context;
- RequestSecurityTokenResponse issuedToken;
- MarshalAsCoordinationContext(transaction, out context, out issuedToken);
- if (issuedToken != null)
- {
- CoordinationServiceSecurity.AddIssuedToken(message, issuedToken);
- }
- WsatTransactionHeader header = new WsatTransactionHeader(context, this.protocolVersion);
- message.Headers.Add(header);
- }
- //=======================================================================================
- void ForcePromotion(Transaction transaction)
- {
- // Force promotion. This may throw TransactionException.
- // We used to check the DistributedIdentifier property first, but VSWhidbey bug 547901
- // prevents us from doing so reliably in multi-threaded scenarios (there is a ----
- // in the System.Transactions code that can cause a NullReferenceException if we ask
- // for the identifier while the transaction is being promoted)
- TransactionInterop.GetTransmitterPropagationToken(transaction);
- }
- //=======================================================================================
- // The demand is not added now (in 4.5), to avoid a breaking change. To be considered in the next version.
- /*
- // We demand full trust because we use CoordinationServiceSecurity from a non-APTCA assembly and CoordinationServiceSecurity.GetIssuedToken(..) can call Environment.FailFast.
- // It's recommended to not let partially trusted callers to bring down the process.
- // WSATs are not supported in partial trust, so customers should not be broken by this demand.
- [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
- */
- public override TransactionInfo ReadTransaction(Message message)
- {
- EnsureInitialized();
- CoordinationContext context = WsatTransactionHeader.GetCoordinationContext(message, this.protocolVersion);
- if (context == null)
- return null;
- // Incoming transaction tokens are optional
- RequestSecurityTokenResponse issuedToken;
- try
- {
- issuedToken = CoordinationServiceSecurity.GetIssuedToken(message, context.Identifier, this.protocolVersion);
- }
- catch (XmlException e)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new TransactionException(SR.FailedToDeserializeIssuedToken, e));
- }
- return new WsatTransactionInfo(this.wsatProxy, context, issuedToken);
- }
- //=======================================================================================
- public WsatTransactionInfo CreateTransactionInfo(CoordinationContext context,
- RequestSecurityTokenResponse issuedToken)
- {
- return new WsatTransactionInfo(this.wsatProxy, context, issuedToken);
- }
- //=======================================================================================
- // The demand is not added now (in 4.5), to avoid a breaking change. To be considered in the next version.
- /*
- // We demand full trust because we use CoordinationContext and CoordinationServiceSecurity from a non-APTCA assembly.
- // The CoordinationContext constructor can call Environment.FailFast and it's recommended to not let partially trusted callers to bring down the process.
- // WSATs are not supported in partial trust, so customers should not be broken by this demand.
- [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
- */
- public void MarshalAsCoordinationContext(Transaction transaction,
- out CoordinationContext context,
- out RequestSecurityTokenResponse issuedToken)
- {
- Guid transactionId = transaction.TransactionInformation.DistributedIdentifier;
- string nonNativeContextId = null;
- context = new CoordinationContext(this.protocolVersion);
- // Get timeout, description and isolation flags
- uint timeout;
- IsolationFlags isoFlags;
- string description;
- OleTxTransactionFormatter.GetTransactionAttributes(transaction,
- out timeout,
- out isoFlags,
- out description);
- context.IsolationFlags = isoFlags;
- context.Description = description;
- // If we can, use cached extended information
- // Note - it may be worth using outgoing contexts more than once.
- // We'll let performance profiling decide that question
- WsatExtendedInformation info;
- if (WsatExtendedInformationCache.Find(transaction, out info))
- {
- context.Expires = info.Timeout;
- // The extended info cache only contains an identifier when it's non-native
- if (!string.IsNullOrEmpty(info.Identifier))
- {
- context.Identifier = info.Identifier;
- nonNativeContextId = info.Identifier;
- }
- }
- else
- {
- context.Expires = timeout;
- if (context.Expires == 0)
- {
- // If the timeout is zero, there are two possibilities:
- // 1) This is a root transaction with an infinite timeout.
- // 2) This is a subordinate transaction whose timeout was not flowed.
- // We have no mechanism for distinguishing between the two cases.
- //
- // We could always return zero here, instead of using the local max timeout.
- // The problem is that the 2004/08 WS-C spec does not specify the meaning
- // of a zero expires field. While we accept zero to mean "as large as possible"
- // it would be risky to expect others to do the same. So we only propagate
- // zero in the expires field if the local max timeout has been disabled.
- //
- // This is MB 34596: how can we flow the real timeout?
- context.Expires = (uint)TimeoutHelper.ToMilliseconds(this.wsatConfig.MaxTimeout);
- }
- }
- if (context.Identifier == null)
- {
- context.Identifier = CoordinationContext.CreateNativeIdentifier(transactionId);
- nonNativeContextId = null;
- }
- string tokenId;
- if (!this.wsatConfig.IssuedTokensEnabled)
- {
- tokenId = null;
- issuedToken = null;
- }
- else
- {
- CoordinationServiceSecurity.CreateIssuedToken(transactionId,
- context.Identifier,
- this.protocolVersion,
- out issuedToken,
- out tokenId);
- }
- AddressHeader refParam = new WsatRegistrationHeader(transactionId, nonNativeContextId, tokenId);
- context.RegistrationService = wsatConfig.CreateRegistrationService(refParam, this.protocolVersion);
- context.IsolationLevel = transaction.IsolationLevel;
- context.LocalTransactionId = transactionId;
- if (this.wsatConfig.OleTxUpgradeEnabled)
- {
- context.PropagationToken = TransactionInterop.GetTransmitterPropagationToken(transaction);
- }
- }
- }
- //------------------------------------------------------------------------------------------
- // Versioned Wsat transaction formatters
- //------------------------------------------------------------------------------------------
- class WsatTransactionFormatter10 : WsatTransactionFormatter
- {
- static WsatTransactionHeader emptyTransactionHeader = new WsatTransactionHeader(null, ProtocolVersion.Version10);
- public WsatTransactionFormatter10() : base(ProtocolVersion.Version10) { }
- //=======================================================================================
- public override MessageHeader EmptyTransactionHeader
- {
- get { return emptyTransactionHeader; }
- }
- }
- class WsatTransactionFormatter11 : WsatTransactionFormatter
- {
- static WsatTransactionHeader emptyTransactionHeader = new WsatTransactionHeader(null, ProtocolVersion.Version11);
- public WsatTransactionFormatter11() : base(ProtocolVersion.Version11) { }
- //=======================================================================================
- public override MessageHeader EmptyTransactionHeader
- {
- get { return emptyTransactionHeader; }
- }
- }
- }
|