with what method getfields example done c# asp.net asp.net-mvc reflection assemblies

c# - what - ASP.NET-AppDomain.CurrentDomain.GetAssemblies()-Faltan ensamblados después de reiniciar AppDomain



what can be done with reflection in c# (2)

Miré a través del código fuente de ASP.NET MVC 2.0 y busqué cómo AreaRegistration.RegisterAllAreas(); está implementado. Esta línea generalmente se coloca en el método Global.asax Application_Start () e internamente escanea todos los ensamblajes para los tipos que implementan el tipo abstracto AreaRegistration. Este es el comportamiento que busco.

Parece que RegisterAllAreas () hace una llamada a BuildManager.GetReferencedAssemblies() , bueno, si es lo suficientemente bueno para MVC, entonces es lo suficientemente bueno para mí :-)

He hecho un poco de experimentación y BuildManager.GetReferencedAssemblies () incluso recogerá adhoc, las DLL aleatorias cayeron en la carpeta / bin, incluso sin referencias a ningún proyecto en la solución de Visual Studio. Por lo tanto, parece mucho más confiable que AppDomain.Current.GetAssemblies() .

He reescrito mi código de localizador de montaje para lo siguiente:

using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Reflection; using System.Web; using System.Web.Compilation; public static class AssemblyLocator { private static readonly ReadOnlyCollection<Assembly> AllAssemblies; private static readonly ReadOnlyCollection<Assembly> BinAssemblies; static AssemblyLocator() { AllAssemblies = new ReadOnlyCollection<Assembly>( BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList()); IList<Assembly> binAssemblies = new List<Assembly>(); string binFolder = HttpRuntime.AppDomainAppPath + "bin//"; IList<string> dllFiles = Directory.GetFiles(binFolder, "*.dll", SearchOption.TopDirectoryOnly).ToList(); foreach (string dllFile in dllFiles) { AssemblyName assemblyName = AssemblyName.GetAssemblyName(dllFile); Assembly locatedAssembly = AllAssemblies.FirstOrDefault(a => AssemblyName.ReferenceMatchesDefinition( a.GetName(), assemblyName)); if (locatedAssembly != null) { binAssemblies.Add(locatedAssembly); } } BinAssemblies = new ReadOnlyCollection<Assembly>(binAssemblies); } public static ReadOnlyCollection<Assembly> GetAssemblies() { return AllAssemblies; } public static ReadOnlyCollection<Assembly> GetBinFolderAssemblies() { return BinAssemblies; } }

Tengo un Bootstrapper que examina todos los ensamblajes en una aplicación ASP.NET MVC para buscar tipos que implementen una interfaz IBootstrapperTask , y luego los registra con un IBootstrapperTask IOC. La idea es que literalmente pueda ubicar sus IBootstrapperTasks en cualquier lugar y organizar sus Proyectos como lo desee.

Código para Bootstrapper:

public class Bootstrapper { static Bootstrapper() { Type bootStrapperType = typeof(IBootstrapperTask); IList<Assembly> assemblies = AppDomain.CurrentDomain.GetAssemblies(); List<Type> tasks = new List<Type>(); foreach (Assembly assembly in assemblies) { var types = from t in assembly.GetTypes() where bootStrapperType.IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract select t; tasks.AddRange(types); } foreach (Type task in tasks) { if (!IocHelper.Container().Kernel.HasComponent(task.FullName)) { IocHelper.Container().AddComponentLifeStyle( task.FullName, task, LifestyleType.Transient); } } } public static void Run() { // Get all registered IBootstrapperTasks, call Execute() method } }

Después de una compilación completa, AppDomain.CurrentDomain.GetAssemblies() devuelve todos los ensamblajes en mi solución (incluidos todos los de GAC, pero eso no me molesta).

Sin embargo, si se reinicia el AppDomain, o si ''reinicio'' el archivo Web.Config (agregando un espacio y guardándolo), el constructor estático se ejecuta nuevamente, pero cuando se llama a AppDomain.CurrentDomain.GetAssemblies() , faltan la mayoría de los ensamblados , incluido el que contiene mis tipos IBootstrapperTask.

¿Cómo puedo solucionar este problema? Supongo que podría System.IO el directorio / bin y cargar todas las DLL allí de forma manual, pero preferiría evitar esto si es posible, ¿o es la única manera? ¿Estoy tomando el enfoque general correcto para esto?

Esta es una aplicación ASP.NET MVC 2.0 que se ejecuta en .NET 4.0, obtengo este problema con el servidor web incorporado de Cassini de Visual Studio 2010 y con IIS7.0 en modo de canalización integrada en Windows Server 2008.

Editar: Acabo de encontrar esta diferencia SO post entre AppDomain.GetAssemblies y BuildManager.GetReferencedAssemblies que dice que AppDomain solo carga los ensambles como se necesitan (por ejemplo, cuando un método / clase de ese ensamblado se llama por primera vez). Supongo que eso explicaría por qué faltan los ensamblados en AppDomain.CurrentDomain.GetAssemblies() ya que Bootstrapper se ejecuta desde el principio.

Me di cuenta de que si hacía una llamada a ''algo'' del ensamblaje que faltaba antes de Bootstrapper, por ejemplo:

public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { MyApp.MissingAssembly.SomeClass someClass = new MyApp.MissingAssembly.SomeClass(); Bootstrapper.Run(); } }

... parece solucionar el problema, pero es un poco complicado.


Parece que resolvió su propio problema.

Editar: Personalmente, en realidad enumeraría los ensamblajes, uno por uno, los cargaré y buscaré la interfaz. Hazlo en base a archivos en lugar de lo que está haciendo el dominio de la aplicación.