PageRenderTime 46ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/Labs/Microsoft.Activities.Extensions/Microsoft.Activities.Extensions/StrictXamlHelper.cs

#
C# | 241 lines | 112 code | 23 blank | 106 comment | 9 complexity | cbe017db4d91ecbe76fda90322cc77ec MD5 | raw file
  1. // --------------------------------------------------------------------------------------------------------------------
  2. // <copyright file="StrictXamlHelper.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // --------------------------------------------------------------------------------------------------------------------
  6. namespace Microsoft.Activities.Extensions
  7. {
  8. using System;
  9. using System.Activities;
  10. using System.Activities.XamlIntegration;
  11. using System.Collections.Generic;
  12. using System.Diagnostics;
  13. using System.Linq;
  14. using System.Reflection;
  15. using System.Xaml;
  16. using System.Xaml.Permissions;
  17. using System.Xml;
  18. /// <summary>
  19. /// Provides helper methods that will apply normal CLR rules for assembly resolution when loading XAML
  20. /// </summary>
  21. /// <remarks>
  22. /// The standard _XamlStaticHelper class generated by the XamlAppDef build task does not apply
  23. /// standard CLR rules when loading assemblies referenced by XAML.
  24. /// For more details see http://blogs.msdn.com/b/rjacobs/archive/2011/01/07/wf4-spike-activity-versioning-gac-and-loose-xaml.aspx
  25. /// For an example of how to use this class see the XAMLAssemblyResolution Example under the Examples folder
  26. /// </remarks>
  27. public static class StrictXamlHelper
  28. {
  29. #region Static Fields
  30. /// <summary>
  31. /// The schema context field.
  32. /// </summary>
  33. private static WeakReference schemaContextField;
  34. #endregion
  35. #region Public Properties
  36. /// <summary>
  37. /// Gets the standard list of referenced assemblies for C# projects.
  38. /// </summary>
  39. /// <remarks>
  40. /// Workflows typically reference a standard list of assemblies.
  41. /// This list will make it easier to create a reference list by combining the two
  42. /// </remarks>
  43. /// <example>
  44. /// ReferencedAssemblies property that adds the StandardReferencedAssemblies collection to it's own
  45. /// <code source="Examples\CSDocExamples\WorkflowCompiled.cs" lang="CSharp" />
  46. /// </example>
  47. public static IEnumerable<string> StandardCSharpReferencedAssemblies
  48. {
  49. get
  50. {
  51. var list = new List<string>
  52. {
  53. "Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
  54. };
  55. list.AddRange(StandardVBReferencedAssemblies);
  56. return list;
  57. }
  58. }
  59. /// <summary>
  60. /// Gets the standard list of referenced assemblies for VB projects.
  61. /// </summary>
  62. /// <remarks>
  63. /// Workflows typically reference a standard list of assemblies.
  64. /// This list will make it easier to create a reference list by combining the two
  65. /// </remarks>
  66. public static IEnumerable<string> StandardVBReferencedAssemblies
  67. {
  68. get
  69. {
  70. return new List<string>
  71. {
  72. "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  73. "System.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
  74. "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  75. "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  76. "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  77. "System.ServiceModel.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
  78. "System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  79. "System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  80. "System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  81. "System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
  82. };
  83. }
  84. }
  85. #endregion
  86. #region Public Methods and Operators
  87. /// <summary>
  88. /// Loads loose XAML and pre-loads the assemblies to ensure correct CLR binding
  89. /// </summary>
  90. /// <param name="activityXaml">
  91. /// The activity xaml.
  92. /// </param>
  93. /// <param name="assemblies">
  94. /// The assemblies.
  95. /// </param>
  96. /// <returns>
  97. /// A <see cref="System.Activities.DynamicActivity"/>
  98. /// </returns>
  99. /// <remarks>
  100. /// ActivityXamlServices.Load will load referenced assemblies using only the assembly name found in the XAML file.
  101. /// The default behavior stores only partial names for references. This means that when the assembly is loaded it
  102. /// will load with a partial name which could result in an unexpected version or entirely different assembly being
  103. /// loaded.
  104. /// As an alternative you can use the &lt;qualifyAssembly&gt; element in your config file to ensure the correct
  105. /// assembly is loaded
  106. /// </remarks>
  107. /// <example>
  108. /// A class that runs loose XAML with an <see cref="XamlAssemblyResolutionOption"/>
  109. /// <code source="Examples\CSDocExamples\LooseXamlExample.cs" lang="CSharp">
  110. /// </code>
  111. /// </example>
  112. [DebuggerNonUserCode]
  113. public static Activity ActivityLoad(string activityXaml, IList<string> assemblies)
  114. {
  115. LoadAssemblies(assemblies);
  116. return ActivityXamlServices.Load(activityXaml);
  117. }
  118. /// <summary>
  119. /// Initializes the Component with strict assembly resolution rules
  120. /// </summary>
  121. /// <param name="component">
  122. /// The component.
  123. /// </param>
  124. /// <param name="resourceName">
  125. /// The resource Name.
  126. /// </param>
  127. /// <param name="assemblies">
  128. /// The referenced assemblies.
  129. /// </param>
  130. /// <typeparam name="T">
  131. /// The type of activity you are initializing
  132. /// </typeparam>
  133. /// <returns>
  134. /// true if content loaded
  135. /// </returns>
  136. /// <remarks>
  137. /// The InitializeComponent method generated by the XamlAppDef build task uses a version independent loading strategy for referenced assemblies.
  138. /// This helper method will ensure that only assemblies provided in the <paramref name="assemblies"/> list will be loaded.
  139. /// </remarks>
  140. /// <example>
  141. /// A overloaded constructor that accepts a <see cref="XamlAssemblyResolutionOption"/>
  142. /// <code source="Examples\CSDocExamples\WorkflowCompiled.cs" lang="CSharp">
  143. /// </code>
  144. /// </example>
  145. [DebuggerNonUserCode]
  146. public static bool InitializeComponent<T>(T component, string resourceName, IList<string> assemblies)
  147. where T : Activity
  148. {
  149. var initializeXaml = typeof(T).Assembly.GetManifestResourceStream(resourceName);
  150. if (initializeXaml == null)
  151. {
  152. throw new InvalidOperationException("Failed to load XAML from manifest resource stream");
  153. }
  154. // Gets the schema context with the list of referenced assemblies
  155. var schemaContext = GetSchemaContext(assemblies);
  156. var readerSettings = new XamlXmlReaderSettings
  157. {
  158. LocalAssembly = Assembly.GetExecutingAssembly(),
  159. AllowProtectedMembersOnRoot = true
  160. };
  161. var writerSettings = new XamlObjectWriterSettings
  162. {
  163. RootObjectInstance = component,
  164. AccessLevel = XamlAccessLevel.PrivateAccessTo(typeof(T))
  165. };
  166. using (var xmlReader = XmlReader.Create(initializeXaml))
  167. using (var reader = new XamlXmlReader(xmlReader, schemaContext, readerSettings))
  168. using (var objectWriter = new XamlObjectWriter(schemaContext, writerSettings))
  169. {
  170. XamlServices.Transform(reader, objectWriter);
  171. }
  172. return true;
  173. }
  174. #endregion
  175. #region Methods
  176. /// <summary>
  177. /// Gets SchemaContext.
  178. /// </summary>
  179. /// <param name="assemblies">
  180. /// The assemblies.
  181. /// </param>
  182. /// <returns>
  183. /// The schema context.
  184. /// </returns>
  185. private static XamlSchemaContext GetSchemaContext(ICollection<string> assemblies = null)
  186. {
  187. XamlSchemaContext xsc;
  188. if (schemaContextField != null)
  189. {
  190. xsc = (XamlSchemaContext)schemaContextField.Target;
  191. if (xsc != null)
  192. {
  193. return xsc;
  194. }
  195. }
  196. xsc = assemblies != null && assemblies.Count > 0
  197. ? new XamlSchemaContext(LoadAssemblies(assemblies))
  198. : new XamlSchemaContext();
  199. schemaContextField = new WeakReference(xsc);
  200. return xsc;
  201. }
  202. /// <summary>
  203. /// Loads a list of assemblies
  204. /// </summary>
  205. /// <param name="assemblies">
  206. /// The assemblies to load.
  207. /// </param>
  208. /// <returns>
  209. /// The list of assemblies loaded
  210. /// </returns>
  211. [DebuggerNonUserCode]
  212. private static IEnumerable<Assembly> LoadAssemblies(IEnumerable<string> assemblies)
  213. {
  214. return assemblies == null ? null : assemblies.Select(Assembly.Load).ToList();
  215. }
  216. #endregion
  217. }
  218. }