PageRenderTime 26ms CodeModel.GetById 10ms app.highlight 11ms 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//===================================================================================
 17using System;
 18using System.Collections.Generic;
 19using System.ComponentModel.Composition;
 20using System.ComponentModel.Composition.Hosting;
 21using System.IO;
 22using Microsoft.Practices.Prism.Modularity;
 23
 24namespace Microsoft.Practices.Prism.MefExtensions.Modularity
 25{
 26    /// <summary>
 27    /// Loads modules from an arbitrary location on the filesystem. This typeloader is only called if 
 28    /// <see cref="ModuleInfo"/> classes have a Ref parameter that starts with "file://". 
 29    /// This class is only used on the Desktop version of the Composite Application Library when used with Managed Extensibility Framework.
 30    /// </summary>  
 31    [Export]
 32    public class MefFileModuleTypeLoader : IModuleTypeLoader
 33    {
 34        private const string RefFilePrefix = "file://";
 35        private readonly HashSet<Uri> downloadedUris = new HashSet<Uri>();
 36
 37        // disable the warning that the field is never assigned to, and will always have its default value null
 38        // as it is imported by MEF
 39#pragma warning disable 0649
 40        [Import(AllowRecomposition = false)]
 41        private AggregateCatalog aggregateCatalog;
 42#pragma warning restore 0649
 43
 44        /// <summary>
 45        /// Initializes a new instance of the MefFileModuleTypeLoader class.
 46        /// This instance is used to load requested module types.
 47        /// </summary>
 48        public MefFileModuleTypeLoader()
 49        {
 50        }
 51
 52        #region IModuleTypeLoader Members
 53
 54        /// <summary>
 55        /// Raised repeatedly to provide progress as modules are loaded in the background.
 56        /// </summary>
 57        public virtual event EventHandler<ModuleDownloadProgressChangedEventArgs> ModuleDownloadProgressChanged;
 58
 59        /// <summary>
 60        /// Raised when a module is loaded or fails to load.
 61        /// </summary>
 62        public virtual event EventHandler<LoadModuleCompletedEventArgs> LoadModuleCompleted;
 63
 64        /// <summary>
 65        /// Evaluates the <see cref="ModuleInfo.Ref"/> property to see if the current typeloader will be able to retrieve the <paramref name="moduleInfo"/>.
 66        /// Returns true if the <see cref="ModuleInfo.Ref"/> property starts with "file://", because this indicates that the file
 67        /// is a local file. 
 68        /// </summary>
 69        /// <param name="moduleInfo">Module that should have it's type loaded.</param>
 70        /// <returns>
 71        ///     <see langword="true"/> if the current typeloader is able to retrieve the module, otherwise <see langword="false"/>.
 72        /// </returns>
 73        public virtual bool CanLoadModuleType(ModuleInfo moduleInfo)
 74        {
 75            if (moduleInfo == null)
 76            {
 77                throw new System.ArgumentNullException("moduleInfo");
 78            }
 79
 80            return moduleInfo.Ref != null && moduleInfo.Ref.StartsWith(RefFilePrefix, StringComparison.Ordinal);
 81        }
 82
 83        /// <summary>
 84        /// Retrieves the <paramref name="moduleInfo"/>.
 85        /// </summary>
 86        /// <param name="moduleInfo">Module that should have it's type loaded.</param>
 87        public virtual void LoadModuleType(ModuleInfo moduleInfo)
 88        {
 89            if (moduleInfo == null)
 90            {
 91                throw new System.ArgumentNullException("moduleInfo");
 92            }
 93
 94            try
 95            {
 96                Uri uri = new Uri(moduleInfo.Ref, UriKind.RelativeOrAbsolute);
 97
 98                // If this module has already been downloaded, I fire the completed event.
 99                if (this.IsSuccessfullyDownloaded(uri))
100                {
101                    this.RaiseLoadModuleCompleted(moduleInfo, null);
102                }
103                else
104                {
105                    string path = moduleInfo.Ref.Substring(RefFilePrefix.Length + 1);
106
107                    long fileSize = -1L;
108                    if (File.Exists(path))
109                    {
110                        FileInfo fileInfo = new FileInfo(path);
111                        fileSize = fileInfo.Length;
112                    }
113
114                    // Although this isn't asynchronous, nor expected to take very long, I raise progress changed for consistency.
115                    this.RaiseModuleDownloadProgressChanged(moduleInfo, 0, fileSize);
116
117                    this.aggregateCatalog.Catalogs.Add(new AssemblyCatalog(path));
118
119                    // Although this isn't asynchronous, nor expected to take very long, I raise progress changed for consistency.
120                    this.RaiseModuleDownloadProgressChanged(moduleInfo, fileSize, fileSize);
121
122                    // I remember the downloaded URI.
123                    this.RecordDownloadSuccess(uri);
124
125                    this.RaiseLoadModuleCompleted(moduleInfo, null);
126                }
127            }
128            catch (Exception ex)
129            {
130                this.RaiseLoadModuleCompleted(moduleInfo, ex);
131            }
132        }
133
134        #endregion
135
136        private void RaiseModuleDownloadProgressChanged(
137            ModuleInfo moduleInfo,
138            long bytesReceived,
139            long totalBytesToReceive)
140        {
141            this.RaiseModuleDownloadProgressChanged(new ModuleDownloadProgressChangedEventArgs(
142                                                        moduleInfo, bytesReceived, totalBytesToReceive));
143        }
144
145        private void RaiseModuleDownloadProgressChanged(ModuleDownloadProgressChangedEventArgs e)
146        {
147            if (this.ModuleDownloadProgressChanged != null)
148            {
149                this.ModuleDownloadProgressChanged(this, e);
150            }
151        }
152
153        private void RaiseLoadModuleCompleted(ModuleInfo moduleInfo, Exception error)
154        {
155            this.RaiseLoadModuleCompleted(new LoadModuleCompletedEventArgs(moduleInfo, error));
156        }
157
158        private void RaiseLoadModuleCompleted(LoadModuleCompletedEventArgs e)
159        {
160            if (this.LoadModuleCompleted != null)
161            {
162                this.LoadModuleCompleted(this, e);
163            }
164        }
165
166        private bool IsSuccessfullyDownloaded(Uri uri)
167        {
168            lock (this.downloadedUris)
169            {
170                return this.downloadedUris.Contains(uri);
171            }
172        }
173
174        private void RecordDownloadSuccess(Uri uri)
175        {
176            lock (this.downloadedUris)
177            {
178                this.downloadedUris.Add(uri);
179            }
180        }
181    }
182}