You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -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
|
||||
}
|
||||
}
|
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user