PageRenderTime 28ms CodeModel.GetById 15ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/V2.2/trunk/CAL/Desktop/Composite/Modularity/AssemblyResolver.Desktop.cs

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