// NAnt - A .NET build tool // Copyright (C) 2001 Gerry Shaw // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Gert Driesen (gert.driesen@ardatis.com) using System; using System.Collections; using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.Remoting.Lifetime; using NAnt.Core; namespace NAnt.Core.Util { /// /// Resolves assemblies by caching assemblies that were loaded. /// [Serializable()] public sealed class AssemblyResolver { #region Public Instance Constructors /// /// Initializes an instanse of the /// class. /// public AssemblyResolver() { _assemblyCache = new Hashtable(); } /// /// Initializes an instanse of the /// class in the context of the given . /// public AssemblyResolver(Task task) : this() { _task = task; } #endregion Public Instance Constructors #region Public Instance Methods /// /// Installs the assembly resolver by hooking up to the /// event. /// public void Attach() { AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyResolve); AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(AssemblyLoad); } /// /// Uninstalls the assembly resolver. /// public void Detach() { AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(this.AssemblyResolve); AppDomain.CurrentDomain.AssemblyLoad -= new AssemblyLoadEventHandler(AssemblyLoad); this._assemblyCache.Clear(); } #endregion Public Instance Methods #region Private Instance Methods /// /// Resolves an assembly not found by the system using the assembly /// cache. /// /// The source of the event. /// A that contains the event data. /// /// The loaded assembly, or if not found. /// private Assembly AssemblyResolve(object sender, ResolveEventArgs args) { bool isFullName = args.Name.IndexOf("Version=") != -1; // first try to find an already loaded assembly Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (isFullName) { if (assembly.FullName == args.Name) { // output debug message Log(Level.Debug, "Resolved assembly '{0}' from" + " loaded assemblies using full name.", args.Name); // return assembly from AppDomain return assembly; } } else if (assembly.GetName(false).Name == args.Name) { // output debug message Log(Level.Debug, "Resolved assembly '{0}' from" + " loaded assemblies using name.", args.Name); // return assembly from AppDomain return assembly; } } // find assembly in cache if (isFullName) { if (_assemblyCache.Contains(args.Name)) { // output debug message Log(Level.Debug, "Resolved assembly '{0}' from" + " cache using full name.", args.Name); // return assembly from cache return (Assembly) _assemblyCache[args.Name]; } } else { foreach (Assembly assembly in _assemblyCache.Values) { if (assembly.GetName(false).Name == args.Name) { // output debug message Log(Level.Debug, "Resolved assembly '{0}'" + " from cache using name.", args.Name); // return assembly from cache return assembly; } } } // output debug message Log(Level.Debug, "Assembly '{0}' could not be located.", args.Name); return null; } /// /// Occurs when an assembly is loaded. The loaded assembly is added /// to the assembly cache. /// /// The source of the event. /// An that contains the event data. private void AssemblyLoad(object sender, AssemblyLoadEventArgs args) { // store assembly in cache _assemblyCache[args.LoadedAssembly.FullName] = args.LoadedAssembly; // output debug message Log(Level.Debug, "Added assembly '{0}' to assembly cache.", args.LoadedAssembly.FullName); } /// /// Logs a message with the given priority. /// /// The message priority at which the specified message is to be logged. /// The message to log, containing zero or more format items. /// An array containing zero or more objects to format. /// /// The actual logging is delegated to the in which /// the is executing /// private void Log(Level messageLevel, string message, params object[] args) { if (_task != null) { _task.Log(messageLevel, message, args); } } #endregion Private Instance Methods #region Private Instance Fields /// /// Holds the loaded assemblies. /// private Hashtable _assemblyCache; /// /// Holds the in which the /// is executing. /// /// /// The in which the /// is executing or if the /// is not executing in the context of a . /// private Task _task; #endregion Private Instance Fields } }