ASP.NET -AppDomain.Dominio actual.GetAssemblies () - Faltan ensamblados después de reiniciar AppDomain


Tengo un Bootstrapper que mira a través de todos los Ensamblados en un ASP.NET MVC aplicación para encontrar tipos que implementan una interfaz IBootstrapperTask, y luego los registra con un IOC Contrainer. La idea es que puedas literalmente colocar tus IBootstrapperTasks en cualquier lugar, y organizar tus Proyectos como quieras.

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 Ensamblados de mi solución (incluidos todos los de GAC one, pero eso no molesta me).

Sin embargo, si el AppDomain se reinicia, o 'reboto' la Web.Archivo de configuración (agregando un espacio y ahorrando), el constructor estático se ejecuta de nuevo, pero cuando se llama AppDomain.CurrentDomain.GetAssemblies(), la mayoría de los Ensamblados faltan, incluido el que contiene mis tipos IBootstrapperTask.

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

Esto es un ASP.NET La aplicación MVC 2.0 que se ejecuta en. NET 4.0, tengo este problema con el servidor web Cassini de Visual Studio 2010 incorporado y con IIS7.0 en Modo de canalización integrada en Windows Server 2008.


Edit: Acabo de encontrarme con esto PARA publicar Diferencia entre AppDomain.GetAssemblies y BuildManager.GetReferencedAssemblies que dice que el AppDomain solo carga los Ensamblados a medida que se necesitan (p. ej. cuando un se llama primero al método/clase de ese Ensamblado). Supongo que eso explicaría por qué faltan los Ensamblados en AppDomain.CurrentDomain.GetAssemblies() ya que el Bootstrapper se ejecuta muy pronto.

Me di cuenta de que si puse una llamada a 'algo' desde el Ensamblado que falta antes del 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 de un hack.

Author: Community, 2010-08-24

2 answers

Miré a través de la ASP.NET MVC 2.0 y buscó cómo se implementa AreaRegistration.RegisterAllAreas();. Esta línea se pone generalmente en el Global.método asax Application_Start () e internamente escanea todos los Ensamblados en busca de tipos que implementen 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 algunos experimentos y BuildManager.GetReferencedAssemblies () incluso recogerá adhoc, DLL aleatorios colocados en la carpeta /bin, incluso sin referencias a ningún proyecto en la solución de Visual Studio. Así que parece mucho más confiable que AppDomain.Current.GetAssemblies().

He reescrito mi código localizador de Ensamblaje a 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;
    }
}
 50
Author: Sunday Ironfoot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-09 15:31:34

Parece que has resuelto tu propio problema.

Editar: Personalmente, en realidad enumeraría los ensamblados, uno por uno, los cargaría y buscaría la interfaz. Hacerlo basado en archivos en lugar de lo que el AppDomain está haciendo.

 1
Author: Nate Zaugg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-23 23:17:05