PageRenderTime 67ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/V4/PrismLibrary/Desktop/Prism.MefExtensions/Modularity/MefFileModuleTypeLoader.Desktop.cs

#
C# | 182 lines | 108 code | 24 blank | 50 comment | 12 complexity | bf41d3b1ad31471ede436b2ad031e759 MD5 | raw file
  1. //===================================================================================
  2. // Microsoft patterns & practices
  3. // Composite Application Guidance for Windows Presentation Foundation and Silverlight
  4. //===================================================================================
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8. // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9. // FITNESS FOR A PARTICULAR PURPOSE.
  10. //===================================================================================
  11. // The example companies, organizations, products, domain names,
  12. // e-mail addresses, logos, people, places, and events depicted
  13. // herein are fictitious. No association with any real company,
  14. // organization, product, domain name, email address, logo, person,
  15. // places, or events is intended or should be inferred.
  16. //===================================================================================
  17. using System;
  18. using System.Collections.Generic;
  19. using System.ComponentModel.Composition;
  20. using System.ComponentModel.Composition.Hosting;
  21. using System.IO;
  22. using Microsoft.Practices.Prism.Modularity;
  23. namespace Microsoft.Practices.Prism.MefExtensions.Modularity
  24. {
  25. /// <summary>
  26. /// Loads modules from an arbitrary location on the filesystem. This typeloader is only called if
  27. /// <see cref="ModuleInfo"/> classes have a Ref parameter that starts with "file://".
  28. /// This class is only used on the Desktop version of the Composite Application Library when used with Managed Extensibility Framework.
  29. /// </summary>
  30. [Export]
  31. public class MefFileModuleTypeLoader : IModuleTypeLoader
  32. {
  33. private const string RefFilePrefix = "file://";
  34. private readonly HashSet<Uri> downloadedUris = new HashSet<Uri>();
  35. // disable the warning that the field is never assigned to, and will always have its default value null
  36. // as it is imported by MEF
  37. #pragma warning disable 0649
  38. [Import(AllowRecomposition = false)]
  39. private AggregateCatalog aggregateCatalog;
  40. #pragma warning restore 0649
  41. /// <summary>
  42. /// Initializes a new instance of the MefFileModuleTypeLoader class.
  43. /// This instance is used to load requested module types.
  44. /// </summary>
  45. public MefFileModuleTypeLoader()
  46. {
  47. }
  48. #region IModuleTypeLoader Members
  49. /// <summary>
  50. /// Raised repeatedly to provide progress as modules are loaded in the background.
  51. /// </summary>
  52. public virtual event EventHandler<ModuleDownloadProgressChangedEventArgs> ModuleDownloadProgressChanged;
  53. /// <summary>
  54. /// Raised when a module is loaded or fails to load.
  55. /// </summary>
  56. public virtual event EventHandler<LoadModuleCompletedEventArgs> LoadModuleCompleted;
  57. /// <summary>
  58. /// Evaluates the <see cref="ModuleInfo.Ref"/> property to see if the current typeloader will be able to retrieve the <paramref name="moduleInfo"/>.
  59. /// Returns true if the <see cref="ModuleInfo.Ref"/> property starts with "file://", because this indicates that the file
  60. /// is a local file.
  61. /// </summary>
  62. /// <param name="moduleInfo">Module that should have it's type loaded.</param>
  63. /// <returns>
  64. /// <see langword="true"/> if the current typeloader is able to retrieve the module, otherwise <see langword="false"/>.
  65. /// </returns>
  66. public virtual bool CanLoadModuleType(ModuleInfo moduleInfo)
  67. {
  68. if (moduleInfo == null)
  69. {
  70. throw new System.ArgumentNullException("moduleInfo");
  71. }
  72. return moduleInfo.Ref != null && moduleInfo.Ref.StartsWith(RefFilePrefix, StringComparison.Ordinal);
  73. }
  74. /// <summary>
  75. /// Retrieves the <paramref name="moduleInfo"/>.
  76. /// </summary>
  77. /// <param name="moduleInfo">Module that should have it's type loaded.</param>
  78. public virtual void LoadModuleType(ModuleInfo moduleInfo)
  79. {
  80. if (moduleInfo == null)
  81. {
  82. throw new System.ArgumentNullException("moduleInfo");
  83. }
  84. try
  85. {
  86. Uri uri = new Uri(moduleInfo.Ref, UriKind.RelativeOrAbsolute);
  87. // If this module has already been downloaded, I fire the completed event.
  88. if (this.IsSuccessfullyDownloaded(uri))
  89. {
  90. this.RaiseLoadModuleCompleted(moduleInfo, null);
  91. }
  92. else
  93. {
  94. string path = moduleInfo.Ref.Substring(RefFilePrefix.Length + 1);
  95. long fileSize = -1L;
  96. if (File.Exists(path))
  97. {
  98. FileInfo fileInfo = new FileInfo(path);
  99. fileSize = fileInfo.Length;
  100. }
  101. // Although this isn't asynchronous, nor expected to take very long, I raise progress changed for consistency.
  102. this.RaiseModuleDownloadProgressChanged(moduleInfo, 0, fileSize);
  103. this.aggregateCatalog.Catalogs.Add(new AssemblyCatalog(path));
  104. // Although this isn't asynchronous, nor expected to take very long, I raise progress changed for consistency.
  105. this.RaiseModuleDownloadProgressChanged(moduleInfo, fileSize, fileSize);
  106. // I remember the downloaded URI.
  107. this.RecordDownloadSuccess(uri);
  108. this.RaiseLoadModuleCompleted(moduleInfo, null);
  109. }
  110. }
  111. catch (Exception ex)
  112. {
  113. this.RaiseLoadModuleCompleted(moduleInfo, ex);
  114. }
  115. }
  116. #endregion
  117. private void RaiseModuleDownloadProgressChanged(
  118. ModuleInfo moduleInfo,
  119. long bytesReceived,
  120. long totalBytesToReceive)
  121. {
  122. this.RaiseModuleDownloadProgressChanged(new ModuleDownloadProgressChangedEventArgs(
  123. moduleInfo, bytesReceived, totalBytesToReceive));
  124. }
  125. private void RaiseModuleDownloadProgressChanged(ModuleDownloadProgressChangedEventArgs e)
  126. {
  127. if (this.ModuleDownloadProgressChanged != null)
  128. {
  129. this.ModuleDownloadProgressChanged(this, e);
  130. }
  131. }
  132. private void RaiseLoadModuleCompleted(ModuleInfo moduleInfo, Exception error)
  133. {
  134. this.RaiseLoadModuleCompleted(new LoadModuleCompletedEventArgs(moduleInfo, error));
  135. }
  136. private void RaiseLoadModuleCompleted(LoadModuleCompletedEventArgs e)
  137. {
  138. if (this.LoadModuleCompleted != null)
  139. {
  140. this.LoadModuleCompleted(this, e);
  141. }
  142. }
  143. private bool IsSuccessfullyDownloaded(Uri uri)
  144. {
  145. lock (this.downloadedUris)
  146. {
  147. return this.downloadedUris.Contains(uri);
  148. }
  149. }
  150. private void RecordDownloadSuccess(Uri uri)
  151. {
  152. lock (this.downloadedUris)
  153. {
  154. this.downloadedUris.Add(uri);
  155. }
  156. }
  157. }
  158. }