e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
209 lines
10 KiB
C#
209 lines
10 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
namespace System.ServiceModel.Channels
|
|
{
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Description;
|
|
using System.ServiceModel.Security;
|
|
using System.Xml;
|
|
using System.Collections.Generic;
|
|
|
|
static class TransactionPolicyStrings
|
|
{
|
|
public const string OptionalLocal = MetadataStrings.WSPolicy.Attributes.Optional;
|
|
public const string OptionalPrefix10 = MetadataStrings.WSPolicy.Prefix + "1";
|
|
public const string OptionalPrefix11 = MetadataStrings.WSPolicy.Prefix;
|
|
public const string OptionalNamespaceLegacy = "http://schemas.xmlsoap.org/ws/2002/12/policy";
|
|
public const string WsatTransactionsPrefix = AtomicTransactionExternalStrings.Prefix;
|
|
public const string WsatTransactionsNamespace10 = AtomicTransactionExternal10Strings.Namespace;
|
|
public const string WsatTransactionsNamespace11 = AtomicTransactionExternal11Strings.Namespace;
|
|
public const string WsatTransactionsLocal = "ATAssertion";
|
|
public const string OleTxTransactionsPrefix = OleTxTransactionExternalStrings.Prefix;
|
|
public const string OleTxTransactionsNamespace = OleTxTransactionExternalStrings.Namespace;
|
|
public const string OleTxTransactionsLocal = "OleTxAssertion";
|
|
public const string TrueValue = "true";
|
|
}
|
|
|
|
public sealed class TransactionFlowBindingElementImporter : IPolicyImportExtension
|
|
{
|
|
void IPolicyImportExtension.ImportPolicy(MetadataImporter importer, PolicyConversionContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
|
|
}
|
|
|
|
// foreach property, we keep track of
|
|
// - everyoneAgreesAbout: all operations agree on a value
|
|
// - anOperationCaresAbout: at least one operation has expressed a preference
|
|
// - agreed value itself (which only matters if anOperationCaresAbout && everyoneAgrees)
|
|
bool everyoneAgreesAboutTransactions = true;
|
|
bool everyoneAgreesAboutTransactionProtocol = true;
|
|
TransactionFlowOption agreedTransactions = TransactionFlowOption.NotAllowed;
|
|
TransactionProtocol agreedTransactionProtocol = TransactionFlowDefaults.TransactionProtocol;
|
|
bool anOperationCaresAboutTransactions = false;
|
|
bool anOperationCaresAboutTransactionProtocol = false;
|
|
|
|
XmlElement oleTxTransactionsAssertion = null;
|
|
XmlElement wsatTransactionsAssertion = null;
|
|
|
|
foreach (OperationDescription operation in context.Contract.Operations)
|
|
{
|
|
ICollection<XmlElement> operationAssertions = context.GetOperationBindingAssertions(operation);
|
|
foreach (XmlElement element in operationAssertions)
|
|
{
|
|
if (element.NamespaceURI == TransactionPolicyStrings.OleTxTransactionsNamespace
|
|
&& element.LocalName == TransactionPolicyStrings.OleTxTransactionsLocal)
|
|
{
|
|
oleTxTransactionsAssertion = element;
|
|
TransactionFlowOption txFlow = GetOption(element, true);
|
|
UpdateTransactionFlowAtribute(operation, txFlow);
|
|
|
|
TrackAgreement(ref everyoneAgreesAboutTransactions,
|
|
txFlow,
|
|
ref agreedTransactions,
|
|
ref anOperationCaresAboutTransactions);
|
|
TrackAgreementTransactionProtocol(ref everyoneAgreesAboutTransactionProtocol,
|
|
TransactionProtocol.OleTransactions,
|
|
ref agreedTransactionProtocol,
|
|
ref anOperationCaresAboutTransactionProtocol);
|
|
}
|
|
else if (element.NamespaceURI == TransactionPolicyStrings.WsatTransactionsNamespace10
|
|
&& element.LocalName == TransactionPolicyStrings.WsatTransactionsLocal)
|
|
{
|
|
wsatTransactionsAssertion = element;
|
|
TransactionFlowOption txFlow = GetOption(element, true);
|
|
UpdateTransactionFlowAtribute(operation, txFlow);
|
|
|
|
TrackAgreement(ref everyoneAgreesAboutTransactions,
|
|
txFlow,
|
|
ref agreedTransactions,
|
|
ref anOperationCaresAboutTransactions);
|
|
TrackAgreementTransactionProtocol(ref everyoneAgreesAboutTransactionProtocol,
|
|
TransactionProtocol.WSAtomicTransactionOctober2004,
|
|
ref agreedTransactionProtocol,
|
|
ref anOperationCaresAboutTransactionProtocol);
|
|
}
|
|
else if (element.NamespaceURI == TransactionPolicyStrings.WsatTransactionsNamespace11
|
|
&& element.LocalName == TransactionPolicyStrings.WsatTransactionsLocal)
|
|
{
|
|
wsatTransactionsAssertion = element;
|
|
TransactionFlowOption txFlow = GetOption(element, false);
|
|
UpdateTransactionFlowAtribute(operation, txFlow);
|
|
|
|
TrackAgreement(ref everyoneAgreesAboutTransactions,
|
|
txFlow,
|
|
ref agreedTransactions,
|
|
ref anOperationCaresAboutTransactions);
|
|
TrackAgreementTransactionProtocol(ref everyoneAgreesAboutTransactionProtocol,
|
|
TransactionProtocol.WSAtomicTransaction11,
|
|
ref agreedTransactionProtocol,
|
|
ref anOperationCaresAboutTransactionProtocol);
|
|
}
|
|
}
|
|
|
|
// remove any imported assertions.
|
|
if (oleTxTransactionsAssertion != null)
|
|
operationAssertions.Remove(oleTxTransactionsAssertion);
|
|
if (wsatTransactionsAssertion != null)
|
|
operationAssertions.Remove(wsatTransactionsAssertion);
|
|
}
|
|
|
|
// setup the ContextFlowBindingElement (if needed) with any agreed-on information
|
|
if (anOperationCaresAboutTransactions)
|
|
{
|
|
TransactionFlowBindingElement tfbe = EnsureBindingElement(context);
|
|
tfbe.Transactions = true;
|
|
|
|
if (anOperationCaresAboutTransactionProtocol && everyoneAgreesAboutTransactionProtocol)
|
|
tfbe.TransactionProtocol = agreedTransactionProtocol;
|
|
else if (anOperationCaresAboutTransactionProtocol)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(
|
|
SR.GetString(SR.SFxCannotHaveDifferentTransactionProtocolsInOneBinding)));
|
|
}
|
|
}
|
|
|
|
void UpdateTransactionFlowAtribute(OperationDescription operation, TransactionFlowOption txFlow)
|
|
{
|
|
operation.Behaviors.Remove<TransactionFlowAttribute>();
|
|
operation.Behaviors.Add(new TransactionFlowAttribute(txFlow));
|
|
}
|
|
|
|
static void TrackAgreement(ref bool everyoneAgrees, TransactionFlowOption option,
|
|
ref TransactionFlowOption agreedOption, ref bool anOperationCares)
|
|
{
|
|
if (!anOperationCares)
|
|
{
|
|
// this is the first operation to express a preference
|
|
agreedOption = option;
|
|
anOperationCares = true;
|
|
// everyoneAgrees is still true
|
|
}
|
|
else
|
|
{
|
|
if (option != agreedOption)
|
|
everyoneAgrees = false;
|
|
}
|
|
}
|
|
|
|
static void TrackAgreementTransactionProtocol(ref bool everyoneAgrees, TransactionProtocol option,
|
|
ref TransactionProtocol agreedOption, ref bool anOperationCares)
|
|
{
|
|
if (!anOperationCares)
|
|
{
|
|
// this is the first operation to express a preference
|
|
agreedOption = option;
|
|
anOperationCares = true;
|
|
// everyoneAgrees is still true
|
|
}
|
|
else
|
|
{
|
|
if (option != agreedOption)
|
|
everyoneAgrees = false;
|
|
}
|
|
}
|
|
|
|
TransactionFlowOption GetOption(XmlElement elem, bool useLegacyNs)
|
|
{
|
|
try
|
|
{
|
|
if (IsRealOptionalTrue(elem) || (useLegacyNs && IsLegacyOptionalTrue(elem)))
|
|
{
|
|
return TransactionFlowOption.Allowed;
|
|
}
|
|
return TransactionFlowOption.Mandatory;
|
|
}
|
|
catch (FormatException e)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(
|
|
SR.GetString(SR.UnsupportedBooleanAttribute, TransactionPolicyStrings.OptionalLocal, e.Message)));
|
|
}
|
|
}
|
|
|
|
static bool IsRealOptionalTrue(XmlElement elem)
|
|
{
|
|
string value12 = elem.GetAttribute(TransactionPolicyStrings.OptionalLocal, MetadataStrings.WSPolicy.NamespaceUri);
|
|
string value15 = elem.GetAttribute(TransactionPolicyStrings.OptionalLocal, MetadataStrings.WSPolicy.NamespaceUri15);
|
|
return XmlUtil.IsTrue(value12) || XmlUtil.IsTrue(value15);
|
|
}
|
|
static bool IsLegacyOptionalTrue(XmlElement elem)
|
|
{
|
|
string valueLegacy = elem.GetAttribute(TransactionPolicyStrings.OptionalLocal, TransactionPolicyStrings.OptionalNamespaceLegacy);
|
|
return XmlUtil.IsTrue(valueLegacy);
|
|
}
|
|
|
|
TransactionFlowBindingElement EnsureBindingElement(PolicyConversionContext context)
|
|
{
|
|
TransactionFlowBindingElement settings = context.BindingElements.Find<TransactionFlowBindingElement>();
|
|
if (settings == null)
|
|
{
|
|
settings = new TransactionFlowBindingElement(false);
|
|
context.BindingElements.Add(settings);
|
|
}
|
|
return settings;
|
|
}
|
|
|
|
}
|
|
}
|