PageRenderTime 23ms CodeModel.GetById 11ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/V4/PrismLibrary/Desktop/Prism/Modularity/AssemblyResolver.Desktop.cs

#
C# | 152 lines | 92 code | 25 blank | 35 comment | 15 complexity | 2955979e0d41a5a264c06d35be4cbc8e 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.IO;
 20using System.Linq;
 21using System.Reflection;
 22using Microsoft.Practices.Prism.Properties;
 23
 24namespace Microsoft.Practices.Prism.Modularity
 25{
 26    /// <summary>
 27    /// Handles AppDomain's AssemblyResolve event to be able to load assemblies dynamically in 
 28    /// the LoadFrom context, but be able to reference the type from assemblies loaded in the Load context.
 29    /// </summary>
 30    public class AssemblyResolver : IAssemblyResolver, IDisposable
 31    {
 32        private readonly List<AssemblyInfo> registeredAssemblies = new List<AssemblyInfo>();
 33
 34        private bool handlesAssemblyResolve;
 35
 36        /// <summary>
 37        /// Registers the specified assembly and resolves the types in it when the AppDomain requests for it.
 38        /// </summary>
 39        /// <param name="assemblyFilePath">The path to the assemly to load in the LoadFrom context.</param>
 40        /// <remarks>This method does not load the assembly immediately, but lazily until someone requests a <see cref="Type"/>
 41        /// declared in the assembly.</remarks>
 42        public void LoadAssemblyFrom(string assemblyFilePath)
 43        {
 44            if (!this.handlesAssemblyResolve)
 45            {
 46                AppDomain.CurrentDomain.AssemblyResolve += this.CurrentDomain_AssemblyResolve;
 47                this.handlesAssemblyResolve = true;
 48            }
 49
 50            Uri assemblyUri = GetFileUri(assemblyFilePath);
 51
 52            if (assemblyUri == null)
 53            {
 54                throw new ArgumentException(Resources.InvalidArgumentAssemblyUri, "assemblyFilePath");
 55            }
 56
 57            if (!File.Exists(assemblyUri.LocalPath))
 58            {
 59                throw new FileNotFoundException();
 60            }
 61
 62            AssemblyName assemblyName = AssemblyName.GetAssemblyName(assemblyUri.LocalPath);
 63            AssemblyInfo assemblyInfo = this.registeredAssemblies.FirstOrDefault(a => assemblyName == a.AssemblyName);
 64
 65            if (assemblyInfo != null)
 66            {
 67                return;
 68            }
 69
 70            assemblyInfo = new AssemblyInfo() { AssemblyName = assemblyName, AssemblyUri = assemblyUri };
 71            this.registeredAssemblies.Add(assemblyInfo);
 72        }
 73
 74        private static Uri GetFileUri(string filePath)
 75        {
 76            if (String.IsNullOrEmpty(filePath))
 77            {
 78                return null;
 79            }
 80
 81            Uri uri;
 82            if (!Uri.TryCreate(filePath, UriKind.Absolute, out uri))
 83            {
 84                return null;
 85            }
 86
 87            if (!uri.IsFile)
 88            {
 89                return null;
 90            }
 91
 92            return uri;
 93        }
 94
 95        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")]
 96        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
 97        {
 98            AssemblyName assemblyName = new AssemblyName(args.Name);
 99
100            AssemblyInfo assemblyInfo = this.registeredAssemblies.FirstOrDefault(a => AssemblyName.ReferenceMatchesDefinition(assemblyName, a.AssemblyName));
101
102            if (assemblyInfo != null)
103            {
104                if (assemblyInfo.Assembly == null)
105                {
106                    assemblyInfo.Assembly = Assembly.LoadFrom(assemblyInfo.AssemblyUri.LocalPath);
107                }
108
109                return assemblyInfo.Assembly;
110            }
111
112            return null;
113        }
114
115        private class AssemblyInfo
116        {
117            public AssemblyName AssemblyName { get; set; }
118
119            public Uri AssemblyUri { get; set; }
120
121            public Assembly Assembly { get; set; }
122        }
123
124        #region Implementation of IDisposable
125
126        /// <summary>
127        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
128        /// </summary>
129        /// <remarks>Calls <see cref="Dispose(bool)"/></remarks>.
130        /// <filterpriority>2</filterpriority>
131        public void Dispose()
132        {
133            this.Dispose(true);
134            GC.SuppressFinalize(this);
135        }
136
137        /// <summary>
138        /// Disposes the associated <see cref="AssemblyResolver"/>.
139        /// </summary>
140        /// <param name="disposing">When <see langword="true"/>, it is being called from the Dispose method.</param>
141        protected virtual void Dispose(bool disposing)
142        {
143            if (this.handlesAssemblyResolve)
144            {
145                AppDomain.CurrentDomain.AssemblyResolve -= this.CurrentDomain_AssemblyResolve;
146                this.handlesAssemblyResolve = false;
147            }
148        }
149
150        #endregion
151    }
152}