TransactionFlowBindingElementImporter.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.ServiceModel;
  7. using System.ServiceModel.Description;
  8. using System.ServiceModel.Security;
  9. using System.Xml;
  10. using System.Collections.Generic;
  11. static class TransactionPolicyStrings
  12. {
  13. public const string OptionalLocal = MetadataStrings.WSPolicy.Attributes.Optional;
  14. public const string OptionalPrefix10 = MetadataStrings.WSPolicy.Prefix + "1";
  15. public const string OptionalPrefix11 = MetadataStrings.WSPolicy.Prefix;
  16. public const string OptionalNamespaceLegacy = "http://schemas.xmlsoap.org/ws/2002/12/policy";
  17. public const string WsatTransactionsPrefix = AtomicTransactionExternalStrings.Prefix;
  18. public const string WsatTransactionsNamespace10 = AtomicTransactionExternal10Strings.Namespace;
  19. public const string WsatTransactionsNamespace11 = AtomicTransactionExternal11Strings.Namespace;
  20. public const string WsatTransactionsLocal = "ATAssertion";
  21. public const string OleTxTransactionsPrefix = OleTxTransactionExternalStrings.Prefix;
  22. public const string OleTxTransactionsNamespace = OleTxTransactionExternalStrings.Namespace;
  23. public const string OleTxTransactionsLocal = "OleTxAssertion";
  24. public const string TrueValue = "true";
  25. }
  26. public sealed class TransactionFlowBindingElementImporter : IPolicyImportExtension
  27. {
  28. void IPolicyImportExtension.ImportPolicy(MetadataImporter importer, PolicyConversionContext context)
  29. {
  30. if (context == null)
  31. {
  32. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
  33. }
  34. // foreach property, we keep track of
  35. // - everyoneAgreesAbout: all operations agree on a value
  36. // - anOperationCaresAbout: at least one operation has expressed a preference
  37. // - agreed value itself (which only matters if anOperationCaresAbout && everyoneAgrees)
  38. bool everyoneAgreesAboutTransactions = true;
  39. bool everyoneAgreesAboutTransactionProtocol = true;
  40. TransactionFlowOption agreedTransactions = TransactionFlowOption.NotAllowed;
  41. TransactionProtocol agreedTransactionProtocol = TransactionFlowDefaults.TransactionProtocol;
  42. bool anOperationCaresAboutTransactions = false;
  43. bool anOperationCaresAboutTransactionProtocol = false;
  44. XmlElement oleTxTransactionsAssertion = null;
  45. XmlElement wsatTransactionsAssertion = null;
  46. foreach (OperationDescription operation in context.Contract.Operations)
  47. {
  48. ICollection<XmlElement> operationAssertions = context.GetOperationBindingAssertions(operation);
  49. foreach (XmlElement element in operationAssertions)
  50. {
  51. if (element.NamespaceURI == TransactionPolicyStrings.OleTxTransactionsNamespace
  52. && element.LocalName == TransactionPolicyStrings.OleTxTransactionsLocal)
  53. {
  54. oleTxTransactionsAssertion = element;
  55. TransactionFlowOption txFlow = GetOption(element, true);
  56. UpdateTransactionFlowAtribute(operation, txFlow);
  57. TrackAgreement(ref everyoneAgreesAboutTransactions,
  58. txFlow,
  59. ref agreedTransactions,
  60. ref anOperationCaresAboutTransactions);
  61. TrackAgreementTransactionProtocol(ref everyoneAgreesAboutTransactionProtocol,
  62. TransactionProtocol.OleTransactions,
  63. ref agreedTransactionProtocol,
  64. ref anOperationCaresAboutTransactionProtocol);
  65. }
  66. else if (element.NamespaceURI == TransactionPolicyStrings.WsatTransactionsNamespace10
  67. && element.LocalName == TransactionPolicyStrings.WsatTransactionsLocal)
  68. {
  69. wsatTransactionsAssertion = element;
  70. TransactionFlowOption txFlow = GetOption(element, true);
  71. UpdateTransactionFlowAtribute(operation, txFlow);
  72. TrackAgreement(ref everyoneAgreesAboutTransactions,
  73. txFlow,
  74. ref agreedTransactions,
  75. ref anOperationCaresAboutTransactions);
  76. TrackAgreementTransactionProtocol(ref everyoneAgreesAboutTransactionProtocol,
  77. TransactionProtocol.WSAtomicTransactionOctober2004,
  78. ref agreedTransactionProtocol,
  79. ref anOperationCaresAboutTransactionProtocol);
  80. }
  81. else if (element.NamespaceURI == TransactionPolicyStrings.WsatTransactionsNamespace11
  82. && element.LocalName == TransactionPolicyStrings.WsatTransactionsLocal)
  83. {
  84. wsatTransactionsAssertion = element;
  85. TransactionFlowOption txFlow = GetOption(element, false);
  86. UpdateTransactionFlowAtribute(operation, txFlow);
  87. TrackAgreement(ref everyoneAgreesAboutTransactions,
  88. txFlow,
  89. ref agreedTransactions,
  90. ref anOperationCaresAboutTransactions);
  91. TrackAgreementTransactionProtocol(ref everyoneAgreesAboutTransactionProtocol,
  92. TransactionProtocol.WSAtomicTransaction11,
  93. ref agreedTransactionProtocol,
  94. ref anOperationCaresAboutTransactionProtocol);
  95. }
  96. }
  97. // remove any imported assertions.
  98. if (oleTxTransactionsAssertion != null)
  99. operationAssertions.Remove(oleTxTransactionsAssertion);
  100. if (wsatTransactionsAssertion != null)
  101. operationAssertions.Remove(wsatTransactionsAssertion);
  102. }
  103. // setup the ContextFlowBindingElement (if needed) with any agreed-on information
  104. if (anOperationCaresAboutTransactions)
  105. {
  106. TransactionFlowBindingElement tfbe = EnsureBindingElement(context);
  107. tfbe.Transactions = true;
  108. if (anOperationCaresAboutTransactionProtocol && everyoneAgreesAboutTransactionProtocol)
  109. tfbe.TransactionProtocol = agreedTransactionProtocol;
  110. else if (anOperationCaresAboutTransactionProtocol)
  111. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(
  112. SR.GetString(SR.SFxCannotHaveDifferentTransactionProtocolsInOneBinding)));
  113. }
  114. }
  115. void UpdateTransactionFlowAtribute(OperationDescription operation, TransactionFlowOption txFlow)
  116. {
  117. operation.Behaviors.Remove<TransactionFlowAttribute>();
  118. operation.Behaviors.Add(new TransactionFlowAttribute(txFlow));
  119. }
  120. static void TrackAgreement(ref bool everyoneAgrees, TransactionFlowOption option,
  121. ref TransactionFlowOption agreedOption, ref bool anOperationCares)
  122. {
  123. if (!anOperationCares)
  124. {
  125. // this is the first operation to express a preference
  126. agreedOption = option;
  127. anOperationCares = true;
  128. // everyoneAgrees is still true
  129. }
  130. else
  131. {
  132. if (option != agreedOption)
  133. everyoneAgrees = false;
  134. }
  135. }
  136. static void TrackAgreementTransactionProtocol(ref bool everyoneAgrees, TransactionProtocol option,
  137. ref TransactionProtocol agreedOption, ref bool anOperationCares)
  138. {
  139. if (!anOperationCares)
  140. {
  141. // this is the first operation to express a preference
  142. agreedOption = option;
  143. anOperationCares = true;
  144. // everyoneAgrees is still true
  145. }
  146. else
  147. {
  148. if (option != agreedOption)
  149. everyoneAgrees = false;
  150. }
  151. }
  152. TransactionFlowOption GetOption(XmlElement elem, bool useLegacyNs)
  153. {
  154. try
  155. {
  156. if (IsRealOptionalTrue(elem) || (useLegacyNs && IsLegacyOptionalTrue(elem)))
  157. {
  158. return TransactionFlowOption.Allowed;
  159. }
  160. return TransactionFlowOption.Mandatory;
  161. }
  162. catch (FormatException e)
  163. {
  164. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(
  165. SR.GetString(SR.UnsupportedBooleanAttribute, TransactionPolicyStrings.OptionalLocal, e.Message)));
  166. }
  167. }
  168. static bool IsRealOptionalTrue(XmlElement elem)
  169. {
  170. string value12 = elem.GetAttribute(TransactionPolicyStrings.OptionalLocal, MetadataStrings.WSPolicy.NamespaceUri);
  171. string value15 = elem.GetAttribute(TransactionPolicyStrings.OptionalLocal, MetadataStrings.WSPolicy.NamespaceUri15);
  172. return XmlUtil.IsTrue(value12) || XmlUtil.IsTrue(value15);
  173. }
  174. static bool IsLegacyOptionalTrue(XmlElement elem)
  175. {
  176. string valueLegacy = elem.GetAttribute(TransactionPolicyStrings.OptionalLocal, TransactionPolicyStrings.OptionalNamespaceLegacy);
  177. return XmlUtil.IsTrue(valueLegacy);
  178. }
  179. TransactionFlowBindingElement EnsureBindingElement(PolicyConversionContext context)
  180. {
  181. TransactionFlowBindingElement settings = context.BindingElements.Find<TransactionFlowBindingElement>();
  182. if (settings == null)
  183. {
  184. settings = new TransactionFlowBindingElement(false);
  185. context.BindingElements.Add(settings);
  186. }
  187. return settings;
  188. }
  189. }
  190. }