Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@@ -0,0 +1,24 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
using System;
namespace System.ServiceModel.Transactions
{
[Flags]
enum IsolationFlags
{
RetainCommitDC = 0x00000001,
RetainCommit = 0x00000002,
RetainCommitNo = 0x00000003,
RetainAbortDC = 0x00000004,
RetainAbort = 0x00000008,
RetainAbortNo = 0x0000000C,
RetainDoNotCare = IsolationFlags.RetainCommitDC | IsolationFlags.RetainAbortDC,
RetainBoth = IsolationFlags.RetainCommit | IsolationFlags.RetainAbort,
RetainNone = IsolationFlags.RetainCommitNo | IsolationFlags.RetainAbortNo,
Optimistic = 0x00000010,
ReadOnly = 0x00000020
}
}

View File

@@ -0,0 +1,39 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System.Transactions;
class OleTxTransactionInfo : TransactionInfo
{
OleTxTransactionHeader header;
public OleTxTransactionInfo(OleTxTransactionHeader header)
{
this.header = header;
}
public override Transaction UnmarshalTransaction()
{
Transaction tx = UnmarshalPropagationToken(header.PropagationToken);
if (this.header.WsatExtendedInformation != null)
this.header.WsatExtendedInformation.TryCache(tx);
return tx;
}
public static Transaction UnmarshalPropagationToken(byte[] propToken)
{
try
{
return TransactionInterop.GetTransactionFromTransmitterPropagationToken(propToken);
}
catch (ArgumentException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TransactionException(SR.GetString(SR.InvalidPropagationToken), e));
}
}
}
}

View File

@@ -0,0 +1,122 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.Runtime.InteropServices;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Transactions;
class OleTxTransactionFormatter : TransactionFormatter
{
static OleTxTransactionHeader emptyTransactionHeader = new OleTxTransactionHeader(null, null);
public override MessageHeader EmptyTransactionHeader
{
get { return emptyTransactionHeader; }
}
public override void WriteTransaction(Transaction transaction, Message message)
{
byte[] propToken = TransactionInterop.GetTransmitterPropagationToken(transaction);
// Find or compute extended information for the transaction
WsatExtendedInformation info;
if (!WsatExtendedInformationCache.Find(transaction, out info))
{
uint timeout = GetTimeoutFromTransaction(transaction);
info = (timeout != 0) ? new WsatExtendedInformation(null, timeout) : null;
}
OleTxTransactionHeader header = new OleTxTransactionHeader(propToken, info);
message.Headers.Add(header);
}
public override TransactionInfo ReadTransaction(Message message)
{
OleTxTransactionHeader header = OleTxTransactionHeader.ReadFrom(message);
if (header == null)
return null;
return new OleTxTransactionInfo(header);
}
public static uint GetTimeoutFromTransaction(Transaction transaction)
{
// For transactions created inside this process, we can ask ITransactionOptions
IDtcTransaction dtcTransaction = TransactionInterop.GetDtcTransaction(transaction);
ITransactionOptions transactionOptions = (ITransactionOptions)dtcTransaction;
XACTOPT options;
transactionOptions.GetOptions(out options);
// For transactions not created inside this process, this will return zero
return options.ulTimeout;
}
public static void GetTransactionAttributes(Transaction transaction,
out uint timeout,
out IsolationFlags isoFlags,
out string description)
{
IDtcTransaction dtcTransaction = TransactionInterop.GetDtcTransaction(transaction);
ITransactionOptions transactionOptions = (ITransactionOptions)dtcTransaction;
ISaneDtcTransaction saneTransaction = (ISaneDtcTransaction)dtcTransaction;
XACTOPT options;
transactionOptions.GetOptions(out options);
// For transactions not created inside this process, this will be zero
timeout = options.ulTimeout;
description = options.szDescription;
XACTTRANSINFO info;
saneTransaction.GetTransactionInfo(out info);
isoFlags = info.isoFlags;
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Ansi)]
struct XACTOPT
{
public uint ulTimeout;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string szDescription;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct XACTTRANSINFO
{
public Guid uow;
public IsolationLevel isoLevel;
public IsolationFlags isoFlags;
public uint grfTCSupported;
public uint grfRMSupported;
public uint grfTCSupportedRetaining;
public uint grfRMSupportedRetaining;
}
[ComImport,
Guid("3A6AD9E0-23B9-11cf-AD60-00AA00A74CCD"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ITransactionOptions
{
void SetOptions([In] ref XACTOPT pOptions);
void GetOptions([Out] out XACTOPT pOptions);
}
[ComImport,
GuidAttribute("0fb15084-af41-11ce-bd2b-204c4f4f5020"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ISaneDtcTransaction
{
void Abort(IntPtr reason, int retaining, int async);
void Commit(int retaining, int commitType, int reserved);
void GetTransactionInfo(out XACTTRANSINFO transactionInformation);
}
}
}

View File

@@ -0,0 +1,208 @@
//------------------------------------------------------------
// 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;
}
}
}

View File

@@ -0,0 +1,145 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.Threading;
using System.Transactions;
using System.Xml;
//------------------------------------------------------------------------------------------
// Transaction caches
//------------------------------------------------------------------------------------------
class WsatExtendedInformationCache : TransactionCache<Transaction, WsatExtendedInformation>
{
public static void Cache(Transaction tx, WsatExtendedInformation info)
{
WsatExtendedInformationCache entry = new WsatExtendedInformationCache();
entry.AddEntry(tx, tx, info);
}
}
class WsatIncomingTransactionCache : TransactionCache<string, Transaction>
{
public static void Cache(string identifier, Transaction tx)
{
WsatIncomingTransactionCache entry = new WsatIncomingTransactionCache();
entry.AddEntry(tx, identifier, tx);
}
}
abstract class TransactionCache<T, S>
{
static Dictionary<T, S> cache = new Dictionary<T, S>();
static ReaderWriterLock cacheLock = new ReaderWriterLock();
T key;
protected void AddEntry(Transaction transaction, T key, S value)
{
this.key = key;
if (Add(key, value))
{
transaction.TransactionCompleted += new TransactionCompletedEventHandler(OnTransactionCompleted);
}
}
void OnTransactionCompleted(object sender, TransactionEventArgs e)
{
Remove(this.key);
}
static bool Add(T key, S value)
{
bool lockHeld = false;
try
{
try { }
finally
{
cacheLock.AcquireWriterLock(Timeout.Infinite);
lockHeld = true;
}
if (!cache.ContainsKey(key))
{
cache.Add(key, value);
return true;
}
}
finally
{
if (lockHeld)
{
cacheLock.ReleaseWriterLock();
}
}
return false;
}
static void Remove(T key)
{
bool lockHeld = false;
try
{
try { }
finally
{
cacheLock.AcquireWriterLock(Timeout.Infinite);
lockHeld = true;
}
bool remove = cache.Remove(key);
if (!(remove))
{
// tx processing requires failfast when state is inconsistent
DiagnosticUtility.FailFast("TransactionCache: key must be present in transaction cache");
}
}
finally
{
if (lockHeld)
{
cacheLock.ReleaseWriterLock();
}
}
}
public static bool Find(T key, out S value)
{
bool lockHeld = false;
try
{
try { }
finally
{
cacheLock.AcquireReaderLock(Timeout.Infinite);
lockHeld = true;
}
if (cache.TryGetValue(key, out value))
{
return true;
}
}
finally
{
if (lockHeld)
{
cacheLock.ReleaseReaderLock();
}
}
return false;
}
}
}

View File

@@ -0,0 +1,91 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.ServiceModel;
using System.Transactions;
abstract class TransactionFormatter
{
static TransactionFormatter oleTxFormatter = new OleTxTransactionFormatter();
static object syncRoot = new object();
public static TransactionFormatter OleTxFormatter
{
get { return oleTxFormatter; }
}
// Double-checked locking pattern requires volatile for read/write synchronization
static volatile TransactionFormatter wsatFormatter10;
public static TransactionFormatter WsatFormatter10
{
get
{
if (wsatFormatter10 == null)
{
lock (syncRoot)
{
if (wsatFormatter10 == null)
{
wsatFormatter10 = new WsatTransactionFormatter10();
}
}
}
return wsatFormatter10;
}
}
// Double-checked locking pattern requires volatile for read/write synchronization
static volatile TransactionFormatter wsatFormatter11;
public static TransactionFormatter WsatFormatter11
{
get
{
if (wsatFormatter11 == null)
{
lock (syncRoot)
{
if (wsatFormatter11 == null)
{
wsatFormatter11 = new WsatTransactionFormatter11();
}
}
}
return wsatFormatter11;
}
}
public abstract MessageHeader EmptyTransactionHeader
{
get;
}
// Write transaction information to a message
//
// Return the transaction protocols that were successfully written to the message
// Throw TransactionException if something goes wrong (e.g., TM comms failure)
public abstract void WriteTransaction(Transaction transaction, Message message);
// Read transaction information from a message
//
// Return a TransactionInfo instance if transaction headers are present in the message
// Return null if no transaction headers are present in the message
// Throw TransactionException if something goes wrong (e.g., malformed XML)
public abstract TransactionInfo ReadTransaction(Message message);
}
abstract class TransactionInfo
{
// Convert transaction information from a message into an actual transaction
//
// Return a transaction instance if successful (fallback down the list of protocols as needed)
// Throw TransactionException if a could not be unmarshaled.
//
// Should not throw an exception
public abstract Transaction UnmarshalTransaction();
}
}

View File

@@ -0,0 +1,183 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
using System.Runtime;
using System.Security.Permissions;
using System.Text;
using Microsoft.Transactions.Wsat.Protocol;
using Microsoft.Transactions.Wsat.Recovery;
class WhereaboutsReader
{
string hostName;
ProtocolInformationReader protocolInfo;
// Whereabouts internals
static Guid GuidWhereaboutsInfo = new Guid("{2adb4462-bd41-11d0-b12e-00c04fc2f3ef}");
const long STmToTmProtocolSize = 4 + 4;
enum TmProtocol
{
TmProtocolNone = 0,
TmProtocolTip = 1,
TmProtocolMsdtcV1 = 2,
TmProtocolMsdtcV2 = 3, // unicode host names in nameobject blobs etc
TmProtocolExtended = 4 // other stuff (e.g., WS-AT)
}
public WhereaboutsReader(byte[] whereabouts)
{
MemoryStream mem = new MemoryStream(whereabouts,
0,
whereabouts.Length,
false,
true); // Enable calls to GetBuffer()
DeserializeWhereabouts(mem);
}
public string HostName
{
get { return this.hostName; }
}
public ProtocolInformationReader ProtocolInformation
{
get { return this.protocolInfo; }
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to SerializationException and SerializationUtils are safe.")]
void DeserializeWhereabouts(MemoryStream mem)
{
// guidSignature
Guid signature = SerializationUtils.ReadGuid(mem);
if (signature != GuidWhereaboutsInfo)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SerializationException(SR.GetString(SR.WhereaboutsSignatureMissing)));
}
// cTmToTmProtocols
uint cTmToTmProtocols = SerializationUtils.ReadUInt(mem);
// Make sure that cTmToTmProtocols is at least plausible
if (cTmToTmProtocols * STmToTmProtocolSize > mem.Length - mem.Position)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SerializationException(SR.GetString(SR.WhereaboutsImplausibleProtocolCount)));
}
// Loop through each protocol
for (uint i = 0; i < cTmToTmProtocols; i++)
{
DeserializeWhereaboutsProtocol(mem);
}
// Require a host name
if (string.IsNullOrEmpty(this.hostName))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SerializationException(SR.GetString(SR.WhereaboutsNoHostName)));
}
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to SerializationUtils are safe.")]
void DeserializeWhereaboutsProtocol(MemoryStream mem)
{
// tmprotDescribed
TmProtocol tmprotDescribed = (TmProtocol)SerializationUtils.ReadInt(mem);
// cbTmProtocolData
uint cbTmProtocolData = SerializationUtils.ReadUInt(mem);
switch (tmprotDescribed)
{
case TmProtocol.TmProtocolMsdtcV2:
ReadMsdtcV2Protocol(mem, cbTmProtocolData);
break;
case TmProtocol.TmProtocolExtended:
ReadExtendedProtocol(mem, cbTmProtocolData);
break;
default:
// We don't care about this protocol
SerializationUtils.IncrementPosition(mem, cbTmProtocolData);
break;
}
// Align the cursor to a 4-byte boundary
SerializationUtils.AlignPosition(mem, 4);
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to SerializationException and SerializationUtils are safe.")]
void ReadMsdtcV2Protocol(MemoryStream mem, uint cbTmProtocolData)
{
const int MaxComputerName = 15;
//
// The host name is encoded in unicode format
// It is followed by a null-terminating unicode character,
// plus some padding to align on 4
//
// Reject host names of disproportionate size
if (cbTmProtocolData > (MaxComputerName + 1) * 2)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SerializationException(SR.GetString(SR.WhereaboutsImplausibleHostNameByteCount)));
}
byte[] chars = SerializationUtils.ReadBytes(mem, (int)cbTmProtocolData);
// Count the bytes until the first null terminating character
int cbString = 0;
while (cbString < cbTmProtocolData - 1 &&
(chars[cbString] != 0 || chars[cbString + 1] != 0))
{
cbString += 2;
}
if (cbString == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SerializationException(SR.GetString(SR.WhereaboutsInvalidHostName)));
}
try
{
this.hostName = Encoding.Unicode.GetString(chars, 0, cbString);
}
catch (ArgumentException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new SerializationException(SR.GetString(SR.WhereaboutsInvalidHostName), e));
}
}
// 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 use ProtocolInformationReader, which is defined in a non-APTCA assembly; WSATs are not supported in partial trust, so customers should not be broken by this demand
*/
void ReadExtendedProtocol(MemoryStream mem, uint cbTmProtocolData)
{
// Read the WSAT1.0 protoocol identifier
Guid guid = SerializationUtils.ReadGuid(mem);
if (guid == PluggableProtocol10.ProtocolGuid || guid == PluggableProtocol11.ProtocolGuid)
{
// This is the WS-AT extended whereabouts blob
this.protocolInfo = new ProtocolInformationReader(mem);
}
else
{
// Some other gateway protocol... Skip the rest of the data
SerializationUtils.IncrementPosition(mem, cbTmProtocolData - 16);
}
}
}
}

View File

@@ -0,0 +1,439 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.IO;
using System.Net;
using System.Security;
using System.ServiceModel.ComIntegration;
using System.ServiceModel.Security;
using System.Transactions;
using Microsoft.Transactions.Wsat.Messaging;
using Microsoft.Transactions.Wsat.Protocol;
using Microsoft.Transactions.Wsat.Recovery;
class TransactionManagerConfigurationException : TransactionException
{
public TransactionManagerConfigurationException(string error, Exception e)
:
base(error, e)
{
}
public TransactionManagerConfigurationException(string error)
:
base(error)
{
}
}
class WsatConfiguration
{
static readonly string DisabledRegistrationPath;
const string WsatKey = @"Software\Microsoft\WSAT\3.0";
const string OleTxUpgradeEnabledValue = "OleTxUpgradeEnabled";
const bool OleTxUpgradeEnabledDefault = true;
bool oleTxUpgradeEnabled;
EndpointAddress localActivationService10;
EndpointAddress localActivationService11;
EndpointAddress remoteActivationService10;
EndpointAddress remoteActivationService11;
Uri registrationServiceAddress10;
Uri registrationServiceAddress11;
bool protocolService10Enabled = false;
bool protocolService11Enabled = false;
bool inboundEnabled;
bool issuedTokensEnabled;
TimeSpan maxTimeout;
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to BindingStrings are safe.")]
static WsatConfiguration()
{
DisabledRegistrationPath = string.Concat(BindingStrings.AddressPrefix, "/", BindingStrings.RegistrationCoordinatorSuffix(ProtocolVersion.Version10), BindingStrings.DisabledSuffix);
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to ProtocolInformationReader.IsV10Enabled and IsV11Enabled are safe.")]
public WsatConfiguration()
{
// Get whereabouts
WhereaboutsReader whereabouts = GetWhereabouts();
ProtocolInformationReader protocol = whereabouts.ProtocolInformation;
if (protocol != null)
{
this.protocolService10Enabled = protocol.IsV10Enabled;
this.protocolService11Enabled = protocol.IsV11Enabled;
}
Initialize(whereabouts);
// Read local registry flag
this.oleTxUpgradeEnabled = ReadFlag(WsatKey, OleTxUpgradeEnabledValue, OleTxUpgradeEnabledDefault);
}
void Initialize(WhereaboutsReader whereabouts)
{
// MB 47153: don't throw system exception if whereabouts data is broken
try
{
InitializeForUnmarshal(whereabouts);
InitializeForMarshal(whereabouts);
}
catch (UriFormatException e)
{
// UriBuilder.Uri can throw this if the URI is ultimately invalid
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionManagerConfigurationException(SR.GetString(SR.WsatUriCreationFailed), e));
}
catch (ArgumentOutOfRangeException e)
{
// UriBuilder constructor can throw this if port < 0
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionManagerConfigurationException(SR.GetString(SR.WsatUriCreationFailed), e));
}
}
public bool OleTxUpgradeEnabled
{
get { return this.oleTxUpgradeEnabled; }
}
public TimeSpan MaxTimeout
{
get { return this.maxTimeout; }
}
public bool IssuedTokensEnabled
{
get { return this.issuedTokensEnabled; }
}
public bool InboundEnabled
{
get { return this.inboundEnabled; }
}
public bool IsProtocolServiceEnabled(ProtocolVersion protocolVersion)
{
switch (protocolVersion)
{
case ProtocolVersion.Version10:
return this.protocolService10Enabled;
case ProtocolVersion.Version11:
return this.protocolService11Enabled;
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
}
}
public EndpointAddress LocalActivationService(ProtocolVersion protocolVersion)
{
switch (protocolVersion)
{
case ProtocolVersion.Version10:
return this.localActivationService10;
case ProtocolVersion.Version11:
return this.localActivationService11;
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
}
}
public EndpointAddress RemoteActivationService(ProtocolVersion protocolVersion)
{
switch (protocolVersion)
{
case ProtocolVersion.Version10:
return this.remoteActivationService10;
case ProtocolVersion.Version11:
return this.remoteActivationService11;
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
}
}
public EndpointAddress CreateRegistrationService(AddressHeader refParam, ProtocolVersion protocolVersion)
{
switch (protocolVersion)
{
case ProtocolVersion.Version10:
return new EndpointAddress(this.registrationServiceAddress10, refParam);
case ProtocolVersion.Version11:
return new EndpointAddress(this.registrationServiceAddress11, refParam);
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
}
}
public bool IsLocalRegistrationService(EndpointAddress endpoint, ProtocolVersion protocolVersion)
{
if (endpoint.Uri == null)
return false;
switch (protocolVersion)
{
case ProtocolVersion.Version10:
return endpoint.Uri == this.registrationServiceAddress10;
case ProtocolVersion.Version11:
return endpoint.Uri == this.registrationServiceAddress11;
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
}
}
public bool IsDisabledRegistrationService(EndpointAddress endpoint)
{
return endpoint.Uri.AbsolutePath == DisabledRegistrationPath;
}
//
// Internals
//
WhereaboutsReader GetWhereabouts()
{
try
{
return new WhereaboutsReader(TransactionInterop.GetWhereabouts());
}
catch (SerializationException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionManagerConfigurationException(SR.GetString(SR.WhereaboutsReadFailed), e));
}
// If GetWhereabouts throws TransactionException, let it propagate
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to the ProtocolInformationReader properties and to BindingStrings.RegistrationCoordinatorSuffix(..) are safe.")]
void InitializeForUnmarshal(WhereaboutsReader whereabouts)
{
ProtocolInformationReader protocol = whereabouts.ProtocolInformation;
if (protocol != null && protocol.NetworkInboundAccess)
{
this.inboundEnabled = true;
bool isTmLocal = string.Compare(Environment.MachineName,
protocol.NodeName,
StringComparison.OrdinalIgnoreCase) == 0;
string spnIdentity;
string activationCoordinatorSuffix10 =
BindingStrings.ActivationCoordinatorSuffix(ProtocolVersion.Version10);
string activationCoordinatorSuffix11 =
BindingStrings.ActivationCoordinatorSuffix(ProtocolVersion.Version11);
if (protocol.IsClustered ||
(protocol.NetworkClientAccess && !isTmLocal))
{
if (protocol.IsClustered)
{
// We cannot reliably perform mutual authentication against a clustered resource
// See MB 43523 for more details on this
spnIdentity = null;
}
else
{
spnIdentity = "host/" + protocol.HostName;
}
if (protocol.IsV10Enabled)
{
this.remoteActivationService10 = CreateActivationEndpointAddress(protocol,
activationCoordinatorSuffix10,
spnIdentity,
true);
}
if (protocol.IsV11Enabled)
{
this.remoteActivationService11 = CreateActivationEndpointAddress(protocol,
activationCoordinatorSuffix11,
spnIdentity,
true);
}
}
if (isTmLocal)
{
spnIdentity = "host/" + protocol.NodeName;
// The net.pipe Activation endpoint uses the host name as a discriminant
// for cluster scenarios with more than one service on a node.
if (protocol.IsV10Enabled)
{
this.localActivationService10 = CreateActivationEndpointAddress(protocol,
activationCoordinatorSuffix10,
spnIdentity,
false);
}
if (protocol.IsV11Enabled)
{
this.localActivationService11 = CreateActivationEndpointAddress(protocol,
activationCoordinatorSuffix11,
spnIdentity,
false);
}
}
}
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to the ProtocolInformationReader properties (HostName, HttpsPort, BasePath) are safe.")]
EndpointAddress CreateActivationEndpointAddress(ProtocolInformationReader protocol,
string suffix,
string spnIdentity,
bool isRemote)
{
string uriScheme;
string host;
int port;
string path;
if (isRemote)
{
uriScheme = Uri.UriSchemeHttps;
host = protocol.HostName;
port = protocol.HttpsPort;
path = protocol.BasePath + "/" + suffix + BindingStrings.RemoteProxySuffix;
}
else
{
uriScheme = Uri.UriSchemeNetPipe;
host = "localhost";
port = -1;
path = protocol.HostName + "/" + protocol.BasePath + "/" + suffix;
}
UriBuilder builder = new UriBuilder(uriScheme, host, port, path);
if (spnIdentity != null)
{
EndpointIdentity identity = EndpointIdentity.CreateSpnIdentity(spnIdentity);
return new EndpointAddress(builder.Uri, identity);
}
else
{
return new EndpointAddress(builder.Uri);
}
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to the ProtocolInformationReader properties and to BindingStrings.RegistrationCoordinatorSuffix(..) are safe.")]
void InitializeForMarshal(WhereaboutsReader whereabouts)
{
ProtocolInformationReader protocol = whereabouts.ProtocolInformation;
if (protocol != null && protocol.NetworkOutboundAccess)
{
// We can marshal outgoing transactions using a valid address
if (protocol.IsV10Enabled)
{
UriBuilder builder10 = new UriBuilder(Uri.UriSchemeHttps,
protocol.HostName,
protocol.HttpsPort,
protocol.BasePath + "/" +
BindingStrings.RegistrationCoordinatorSuffix(ProtocolVersion.Version10));
this.registrationServiceAddress10 = builder10.Uri;
}
// when we have a WSAT1.1 coordinator
if (protocol.IsV11Enabled)
{
UriBuilder builder11 = new UriBuilder(Uri.UriSchemeHttps,
protocol.HostName,
protocol.HttpsPort,
protocol.BasePath + "/" +
BindingStrings.RegistrationCoordinatorSuffix(ProtocolVersion.Version11));
this.registrationServiceAddress11 = builder11.Uri;
}
this.issuedTokensEnabled = protocol.IssuedTokensEnabled;
this.maxTimeout = protocol.MaxTimeout;
}
else
{
// Generate an address that will not work
// We do this in order to generate coordination contexts that can be propagated
// between processes on the same node even if WS-AT is disabled
UriBuilder builder = new UriBuilder(Uri.UriSchemeHttps,
whereabouts.HostName,
443,
DisabledRegistrationPath);
this.registrationServiceAddress10 = builder.Uri;
this.registrationServiceAddress11 = builder.Uri;
this.issuedTokensEnabled = false;
this.maxTimeout = TimeSpan.FromMinutes(5);
}
}
static object ReadValue(string key, string value)
{
try
{
using (RegistryHandle regKey = RegistryHandle.GetNativeHKLMSubkey(key, false))
{
if (regKey == null)
return null;
return regKey.GetValue(value);
}
}
catch (SecurityException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionManagerConfigurationException(SR.GetString(SR.WsatRegistryValueReadError, value), e));
}
catch (IOException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionManagerConfigurationException(SR.GetString(SR.WsatRegistryValueReadError, value), e));
}
}
static int ReadInt(string key, string value, int defaultValue)
{
object regValue = ReadValue(key, value);
if (regValue == null || !(regValue is Int32))
return defaultValue;
return (int)regValue;
}
static bool ReadFlag(string key, string value, bool defaultValue)
{
return (int)ReadInt(key, value, defaultValue ? 1 : 0) != 0;
}
}
}

View File

@@ -0,0 +1,60 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System.Transactions;
class WsatExtendedInformation
{
string identifier;
uint timeout;
public WsatExtendedInformation(string identifier, uint timeout)
{
this.identifier = identifier;
this.timeout = timeout;
}
public string Identifier
{
get { return this.identifier; }
}
public uint Timeout
{
get { return this.timeout; }
}
public void TryCache(Transaction tx)
{
Guid transactionId = tx.TransactionInformation.DistributedIdentifier;
bool nativeId = IsNativeIdentifier(this.identifier, transactionId);
string cacheIdentifier = nativeId ? null : this.identifier;
if (!string.IsNullOrEmpty(cacheIdentifier) || this.timeout != 0)
{
// Cache extended information for subsequent marshal operations
WsatExtendedInformationCache.Cache(tx, new WsatExtendedInformation(cacheIdentifier,
this.timeout));
}
}
// Copied Helper method from CoordinationContext so we don't have to have this type
public const string UuidScheme = "urn:uuid:";
public static string CreateNativeIdentifier(Guid transactionId)
{
return UuidScheme + transactionId.ToString("D");
}
public static bool IsNativeIdentifier(string identifier, Guid transactionId)
{
return string.Compare(identifier,
CreateNativeIdentifier(transactionId),
StringComparison.Ordinal) == 0;
}
}
}

View File

@@ -0,0 +1,481 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime;
using System.Runtime.InteropServices;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Transactions;
using System.ServiceModel.Security;
using System.ServiceModel.Diagnostics;
using Microsoft.Transactions.Bridge;
using Microsoft.Transactions.Wsat.Messaging;
using Microsoft.Transactions.Wsat.Protocol;
using DiagnosticUtility = System.ServiceModel.DiagnosticUtility;
using System.Security.Permissions;
class WsatProxy
{
WsatConfiguration wsatConfig;
ProtocolVersion protocolVersion;
CoordinationService coordinationService;
ActivationProxy activationProxy;
object proxyLock = new object();
public WsatProxy(WsatConfiguration wsatConfig, ProtocolVersion protocolVersion)
{
this.wsatConfig = wsatConfig;
this.protocolVersion = protocolVersion;
}
//=============================================================================================
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls to CoordinationContext properties are safe.")]
public Transaction UnmarshalTransaction(WsatTransactionInfo info)
{
if (info.Context.ProtocolVersion != this.protocolVersion)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new ArgumentException(SR.GetString(SR.InvalidWsatProtocolVersion)));
}
if (wsatConfig.OleTxUpgradeEnabled)
{
byte[] propToken = info.Context.PropagationToken;
if (propToken != null)
{
try
{
return OleTxTransactionInfo.UnmarshalPropagationToken(propToken);
}
catch (TransactionException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
}
// Fall back to WS-AT unmarshal
if (DiagnosticUtility.ShouldTraceInformation)
TraceUtility.TraceEvent(TraceEventType.Information,
TraceCode.TxFailedToNegotiateOleTx,
SR.GetString(SR.TraceCodeTxFailedToNegotiateOleTx, info.Context.Identifier));
}
}
// Optimization: if the context's registration service points to our local TM, we can
// skip the CreateCoordinationContext step
CoordinationContext localContext = info.Context;
if (!this.wsatConfig.IsLocalRegistrationService(localContext.RegistrationService, this.protocolVersion))
{
// Our WS-AT protocol service for the context's protocol version should be enabled
if (!this.wsatConfig.IsProtocolServiceEnabled(this.protocolVersion))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionException(SR.GetString(SR.WsatProtocolServiceDisabled, this.protocolVersion)));
}
// We should have enabled inbound transactions
if (!this.wsatConfig.InboundEnabled)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionException(SR.GetString(SR.InboundTransactionsDisabled)));
}
// The sender should have enabled both WS-AT and outbound transactions
if (this.wsatConfig.IsDisabledRegistrationService(localContext.RegistrationService))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionException(SR.GetString(SR.SourceTransactionsDisabled)));
}
// Ask the WS-AT protocol service to unmarshal the transaction
localContext = CreateCoordinationContext(info);
}
Guid transactionId = localContext.LocalTransactionId;
if (transactionId == Guid.Empty)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionException(SR.GetString(SR.InvalidCoordinationContextTransactionId)));
}
byte[] propagationToken = MarshalPropagationToken(ref transactionId,
localContext.IsolationLevel,
localContext.IsolationFlags,
localContext.Description);
return OleTxTransactionInfo.UnmarshalPropagationToken(propagationToken);
}
//=============================================================================================
// 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 CreateCoordinationContext from a non-APTCA assembly and the CreateCoordinationContext constructor does an Environment.FailFast
// if the argument is invalid. 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)]
*/
CoordinationContext CreateCoordinationContext(WsatTransactionInfo info)
{
CreateCoordinationContext cccMessage = new CreateCoordinationContext(this.protocolVersion);
cccMessage.CurrentContext = info.Context;
cccMessage.IssuedToken = info.IssuedToken;
try
{
// This was necessary during some portions of WCF 1.0 development
// It is probably not needed now. However, it seems conceptually
// solid to separate this operation from the incoming app message as
// much as possible. There have also been enough ServiceModel bugs in
// this area that it does not seem wise to remove this at the moment
// (2006/3/30, WCF 1.0 RC1 milestone)
using (new OperationContextScope((OperationContext)null))
{
return Enlist(ref cccMessage).CoordinationContext;
}
}
catch (WsatFaultException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionException(SR.GetString(SR.UnmarshalTransactionFaulted, e.Message), e));
}
catch (WsatSendFailureException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionManagerCommunicationException(SR.GetString(SR.TMCommunicationError), e));
}
}
//=============================================================================================
// 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
*/
CreateCoordinationContextResponse Enlist(ref CreateCoordinationContext cccMessage)
{
int attempts = 0;
while (true)
{
ActivationProxy proxy = GetActivationProxy();
EndpointAddress address = proxy.To;
EndpointAddress localActivationService = this.wsatConfig.LocalActivationService(this.protocolVersion);
EndpointAddress remoteActivationService = this.wsatConfig.RemoteActivationService(this.protocolVersion);
try
{
return proxy.SendCreateCoordinationContext(ref cccMessage);
}
catch (WsatSendFailureException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
// Don't retry if we're not likely to succeed on the next pass
Exception inner = e.InnerException;
if (inner is TimeoutException ||
inner is QuotaExceededException ||
inner is FaultException)
throw;
// Give up after 10 attempts
if (attempts > 10)
throw;
if (attempts > 5 &&
remoteActivationService != null &&
ReferenceEquals(address, localActivationService))
{
// Switch over to the remote activation service.
// In clustered scenarios this uses the cluster name,
// so it should always work if the resource is online
// This covers the case where we were using a local cluster
// resource which failed over to another node
address = remoteActivationService;
}
}
finally
{
proxy.Release();
}
TryStartMsdtcService();
// We need to refresh our proxy here because the channel is sessionful
// and may simply decided to enter the faulted state if something fails.
RefreshActivationProxy(address);
// Don't spin
Thread.Sleep(0);
attempts++;
}
}
//=============================================================================================
void TryStartMsdtcService()
{
try
{
TransactionInterop.GetWhereabouts();
}
catch (TransactionException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
}
}
//=============================================================================================
// 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 call ActivationProxy.AddRef(), which is defined in a non-APTCA assembly and can do 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)]
*/
ActivationProxy GetActivationProxy()
{
if (this.activationProxy == null)
{
RefreshActivationProxy(null);
}
lock (this.proxyLock)
{
ActivationProxy proxy = this.activationProxy;
proxy.AddRef();
return proxy;
}
}
//=============================================================================================
// 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 call ActivationProxy.Release(), which is defined in a non-APTCA assembly and can do 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)]
*/
void RefreshActivationProxy(EndpointAddress suggestedAddress)
{
// Pick an address in the following order...
EndpointAddress address = suggestedAddress;
if (address == null)
{
address = this.wsatConfig.LocalActivationService(this.protocolVersion);
if (address == null)
{
address = this.wsatConfig.RemoteActivationService(this.protocolVersion);
}
}
if (!(address != null))
{
// tx processing requires failfast when state is inconsistent
DiagnosticUtility.FailFast("Must have valid activation service address");
}
lock (this.proxyLock)
{
ActivationProxy newProxy = CreateActivationProxy(address);
if (this.activationProxy != null)
this.activationProxy.Release();
this.activationProxy = newProxy;
}
}
//=============================================================================================
// 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
*/
ActivationProxy CreateActivationProxy(EndpointAddress address)
{
CoordinationService coordination = GetCoordinationService();
try
{
return coordination.CreateActivationProxy(address, false);
}
catch (CreateChannelFailureException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionException(SR.GetString(SR.WsatProxyCreationFailed), e));
}
}
//=============================================================================================
//[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "We call PartialTrustHelpers.DemandForFullTrust().")]
CoordinationService GetCoordinationService()
{
if (this.coordinationService == null)
{
lock (this.proxyLock)
{
if (this.coordinationService == null)
{
// 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 CoordinationService is defined in a non-APTCA assembly and can call Environment.FailFast.
// It's recommended to not let partially trusted callers to bring down the process.
System.Runtime.PartialTrustHelpers.DemandForFullTrust();
*/
try
{
CoordinationServiceConfiguration config = new CoordinationServiceConfiguration();
config.Mode = CoordinationServiceMode.Formatter;
config.RemoteClientsEnabled = this.wsatConfig.RemoteActivationService(this.protocolVersion) != null;
this.coordinationService = new CoordinationService(config, this.protocolVersion);
}
catch (MessagingInitializationException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new TransactionException(SR.GetString(SR.WsatMessagingInitializationFailed), e));
}
}
}
}
return this.coordinationService;
}
//-------------------------------------------------------------------------------
// Marshal/Unmarshaling related stuff
//-------------------------------------------------------------------------------
// Keep a propagation token around as a template for hydrating transactions
static byte[] fixedPropagationToken;
static byte[] CreateFixedPropagationToken()
{
if (fixedPropagationToken == null)
{
CommittableTransaction tx = new CommittableTransaction();
byte[] token = TransactionInterop.GetTransmitterPropagationToken(tx);
// Don't abort the transaction. People notice this and do not like it.
try
{
tx.Commit();
}
catch (TransactionException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
}
Interlocked.CompareExchange<byte[]>(ref fixedPropagationToken, token, null);
}
byte[] tokenCopy = new byte[fixedPropagationToken.Length];
Array.Copy(fixedPropagationToken, tokenCopy, fixedPropagationToken.Length);
return tokenCopy;
}
// This is what a propagation token looks like:
//
// struct PropagationToken
// {
// DWORD dwVersionMin;
// DWORD dwVersionMax;
// GUID guidTx;
// ISOLATIONLEVEL isoLevel;
// ISOFLAG isoFlags;
// ULONG cbSourceTmAddr;
// char szDesc[40];
// [etc]
// }
static byte[] MarshalPropagationToken(ref Guid transactionId,
IsolationLevel isoLevel,
IsolationFlags isoFlags,
string description)
{
const int offsetof_guidTx = 8;
const int offsetof_isoLevel = 24;
const int offsetof_isoFlags = 28;
const int offsetof_szDesc = 36;
const int MaxDescriptionLength = 39;
byte[] token = CreateFixedPropagationToken();
// Replace transaction id
byte[] transactionIdBytes = transactionId.ToByteArray();
Array.Copy(transactionIdBytes, 0, token, offsetof_guidTx, transactionIdBytes.Length);
// Replace isolation level
byte[] isoLevelBytes = BitConverter.GetBytes((int)ConvertIsolationLevel(isoLevel));
Array.Copy(isoLevelBytes, 0, token, offsetof_isoLevel, isoLevelBytes.Length);
// Replace isolation flags
byte[] isoFlagsBytes = BitConverter.GetBytes((int)isoFlags);
Array.Copy(isoFlagsBytes, 0, token, offsetof_isoFlags, isoFlagsBytes.Length);
// Replace description
if (!string.IsNullOrEmpty(description))
{
byte[] descriptionBytes = Encoding.UTF8.GetBytes(description);
int copyDescriptionBytes = Math.Min(descriptionBytes.Length, MaxDescriptionLength);
Array.Copy(descriptionBytes, 0, token, offsetof_szDesc, copyDescriptionBytes);
token[offsetof_szDesc + copyDescriptionBytes] = 0;
}
return token;
}
enum ProxyIsolationLevel : int
{
Unspecified = -1,
Chaos = 0x10,
ReadUncommitted = 0x100,
Browse = 0x100,
CursorStability = 0x1000,
ReadCommitted = 0x1000,
RepeatableRead = 0x10000,
Serializable = 0x100000,
Isolated = 0x100000
}
static ProxyIsolationLevel ConvertIsolationLevel(IsolationLevel IsolationLevel)
{
ProxyIsolationLevel retVal;
switch (IsolationLevel)
{
case IsolationLevel.Serializable:
retVal = ProxyIsolationLevel.Serializable;
break;
case IsolationLevel.RepeatableRead:
retVal = ProxyIsolationLevel.RepeatableRead;
break;
case IsolationLevel.ReadCommitted:
retVal = ProxyIsolationLevel.ReadCommitted;
break;
case IsolationLevel.ReadUncommitted:
retVal = ProxyIsolationLevel.ReadUncommitted;
break;
case IsolationLevel.Unspecified:
retVal = ProxyIsolationLevel.Unspecified;
break;
default:
retVal = ProxyIsolationLevel.Serializable;
break;
}
return retVal;
}
}
}

View File

@@ -0,0 +1,199 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.ServiceModel;
using System.Xml;
using Microsoft.Transactions.Wsat.Messaging;
using XD = System.ServiceModel.XD;
using System.Diagnostics.CodeAnalysis;
using System.Runtime;
class WsatRegistrationHeader : AddressHeader
{
const string HeaderName = DotNetAtomicTransactionExternalStrings.RegisterInfo;
const string HeaderNamespace = DotNetAtomicTransactionExternalStrings.Namespace;
Guid transactionId;
string contextId;
string tokenId;
public WsatRegistrationHeader(Guid transactionId, string contextId, string tokenId)
{
this.transactionId = transactionId;
this.contextId = contextId;
this.tokenId = tokenId;
}
public override string Name
{
get { return HeaderName; }
}
public override string Namespace
{
get { return HeaderNamespace; }
}
public Guid TransactionId
{
get { return this.transactionId; }
}
public string ContextId
{
get { return this.contextId; }
}
public string TokenId
{
get { return this.tokenId; }
}
protected override void OnWriteStartAddressHeader (XmlDictionaryWriter writer)
{
writer.WriteStartElement(DotNetAtomicTransactionExternalStrings.Prefix,
XD.DotNetAtomicTransactionExternalDictionary.RegisterInfo,
XD.DotNetAtomicTransactionExternalDictionary.Namespace);
}
protected override void OnWriteAddressHeaderContents (XmlDictionaryWriter writer)
{
writer.WriteStartElement(XD.DotNetAtomicTransactionExternalDictionary.LocalTransactionId,
XD.DotNetAtomicTransactionExternalDictionary.Namespace);
writer.WriteValue(this.transactionId);
writer.WriteEndElement();
if (this.contextId != null)
{
writer.WriteStartElement(XD.DotNetAtomicTransactionExternalDictionary.ContextId,
XD.DotNetAtomicTransactionExternalDictionary.Namespace);
writer.WriteValue(this.contextId);
writer.WriteEndElement();
}
if (this.tokenId != null)
{
writer.WriteStartElement(XD.DotNetAtomicTransactionExternalDictionary.TokenId,
XD.DotNetAtomicTransactionExternalDictionary.Namespace);
writer.WriteValue(this.tokenId);
writer.WriteEndElement();
}
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The call to InvalidEnlistmentHeaderException is safe.")]
public static WsatRegistrationHeader ReadFrom(Message message)
{
int index;
try
{
index = message.Headers.FindHeader(HeaderName, HeaderNamespace);
}
catch (MessageHeaderException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
return null;
}
if (index < 0)
{
return null;
}
WsatRegistrationHeader header;
XmlDictionaryReader reader = message.Headers.GetReaderAtHeader(index);
using (reader)
{
try
{
header = ReadFrom(reader);
}
catch (XmlException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidEnlistmentHeaderException(e.Message, e));
}
}
MessageHeaderInfo headerInfo = message.Headers[index];
if (!message.Headers.UnderstoodHeaders.Contains(headerInfo))
{
message.Headers.UnderstoodHeaders.Add(headerInfo);
}
return header;
}
static WsatRegistrationHeader ReadFrom(XmlDictionaryReader reader)
{
reader.ReadFullStartElement(XD.DotNetAtomicTransactionExternalDictionary.RegisterInfo,
XD.DotNetAtomicTransactionExternalDictionary.Namespace);
reader.MoveToStartElement(XD.DotNetAtomicTransactionExternalDictionary.LocalTransactionId,
XD.DotNetAtomicTransactionExternalDictionary.Namespace);
// TransactionId
Guid transactionId = reader.ReadElementContentAsGuid();
if (transactionId == Guid.Empty)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new XmlException(SR.GetString(SR.InvalidRegistrationHeaderTransactionId)));
}
// ContextId
string contextId;
if (reader.IsStartElement(XD.DotNetAtomicTransactionExternalDictionary.ContextId,
XD.DotNetAtomicTransactionExternalDictionary.Namespace))
{
Uri uri;
contextId = reader.ReadElementContentAsString().Trim();
if (contextId.Length == 0 ||
contextId.Length > CoordinationContext.MaxIdentifierLength ||
!Uri.TryCreate(contextId, UriKind.Absolute, out uri))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new XmlException(SR.GetString(SR.InvalidRegistrationHeaderIdentifier)));
}
}
else
{
contextId = null;
}
// TokenId
string tokenId;
if (reader.IsStartElement(XD.DotNetAtomicTransactionExternalDictionary.TokenId,
XD.DotNetAtomicTransactionExternalDictionary.Namespace))
{
tokenId = reader.ReadElementContentAsString().Trim();
if (tokenId.Length == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new XmlException(SR.GetString(SR.InvalidRegistrationHeaderTokenId)));
}
}
else
{
tokenId = null;
}
// Skip unknown elements
while (reader.IsStartElement())
{
reader.Skip();
}
reader.ReadEndElement();
return new WsatRegistrationHeader(transactionId, contextId, tokenId);
}
}
}

View File

@@ -0,0 +1,245 @@
//------------------------------------------------------------
// 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; }
}
}
}

View File

@@ -0,0 +1,131 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime;
using System.ServiceModel.Channels;
using System.Diagnostics;
using System.ServiceModel;
using System.Transactions;
using System.Xml;
using Microsoft.Transactions.Wsat.Messaging;
using Microsoft.Transactions.Wsat.Protocol;
using System.Security.Permissions;
class WsatTransactionHeader : MessageHeader
{
string wsatHeaderElement;
string wsatNamespace;
CoordinationContext context;
// 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 call into CoordinationStrings.Version(..), which is defined in a non-APTCA assembly and does an Environment.FailFast
// if the argument is invalid. 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 WsatTransactionHeader(CoordinationContext context, ProtocolVersion protocolVersion)
{
this.context = context;
CoordinationStrings coordinationStrings = CoordinationStrings.Version(protocolVersion);
this.wsatHeaderElement = coordinationStrings.CoordinationContext;
this.wsatNamespace = coordinationStrings.Namespace;
}
public override bool MustUnderstand
{
get { return true; }
}
public override string Name
{
get { return wsatHeaderElement; }
}
public override string Namespace
{
get { return wsatNamespace; }
}
// 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 call into CoordinationContext and CoordinationStrings, which are defined in a non-APTCA assembly. Also, CoordinationStrings.Version(..)
// does an Environment.FailFast if the argument is invalid. 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 static CoordinationContext GetCoordinationContext(Message message, ProtocolVersion protocolVersion)
{
CoordinationStrings coordinationStrings = CoordinationStrings.Version(protocolVersion);
string locWsatHeaderElement = coordinationStrings.CoordinationContext;
string locWsatNamespace = coordinationStrings.Namespace;
int index;
try
{
index = message.Headers.FindHeader(locWsatHeaderElement, locWsatNamespace);
}
catch (MessageHeaderException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
return null;
}
if (index < 0)
return null;
CoordinationContext context;
XmlDictionaryReader reader = message.Headers.GetReaderAtHeader(index);
using (reader)
{
context = GetCoordinationContext(reader, protocolVersion);
}
MessageHeaderInfo header = message.Headers[index];
if (!message.Headers.UnderstoodHeaders.Contains(header))
{
message.Headers.UnderstoodHeaders.Add(header);
}
return context;
}
// 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 into CoordinationContext, which is defined in a non-APTCA assembly; WSATs are not supported in partial trust, so customers should not be broken by this demand
*/
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
this.context.WriteContent(writer);
}
// 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 call into CoordinationXmlDictionaryStrings.Version(..), which is defined in a non-APTCA assembly and does an Environment.FailFast
// if the argument is invalid. 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 static CoordinationContext GetCoordinationContext(XmlDictionaryReader reader, ProtocolVersion protocolVersion)
{
CoordinationXmlDictionaryStrings coordinationXmlDictionaryStrings =
CoordinationXmlDictionaryStrings.Version(protocolVersion);
try
{
return CoordinationContext.ReadFrom(reader,
coordinationXmlDictionaryStrings.CoordinationContext,
coordinationXmlDictionaryStrings.Namespace,
protocolVersion);
}
catch (InvalidCoordinationContextException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Error);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TransactionException(SR.GetString(SR.WsatHeaderCorrupt), e));
}
}
}
}

View File

@@ -0,0 +1,57 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Transactions
{
using System.Diagnostics.CodeAnalysis;
using System.Runtime;
using System.ServiceModel.Security;
using System.Transactions;
using Microsoft.Transactions.Wsat.Messaging;
class WsatTransactionInfo : TransactionInfo
{
WsatProxy wsatProxy;
CoordinationContext context;
RequestSecurityTokenResponse issuedToken;
public WsatTransactionInfo(WsatProxy wsatProxy,
CoordinationContext context,
RequestSecurityTokenResponse issuedToken)
{
this.wsatProxy = wsatProxy;
this.context = context;
this.issuedToken = issuedToken;
}
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.AptcaMethodsShouldOnlyCallAptcaMethods, Justification = "The calls into CoordinationContext are safe.")]
public override Transaction UnmarshalTransaction()
{
Transaction tx;
if (WsatIncomingTransactionCache.Find(this.context.Identifier, out tx))
return tx;
tx = this.wsatProxy.UnmarshalTransaction(this);
// Cache extended information for subsequent marshal operations
WsatExtendedInformation info = new WsatExtendedInformation(context.Identifier, context.Expires);
info.TryCache(tx);
// Cache the unmarshalled transaction for subsequent unmarshal operations
WsatIncomingTransactionCache.Cache(this.context.Identifier, tx);
return tx;
}
public CoordinationContext Context
{
get { return this.context; }
}
public RequestSecurityTokenResponse IssuedToken
{
get { return this.issuedToken; }
}
}
}