ASP.NET - AppDomain.CurrentDomain.GetAssemblies() - AppDomain 重启后程序集丢失 [英] ASP.NET - AppDomain.CurrentDomain.GetAssemblies() - Assemblies missing after AppDomain restart

查看:29
本文介绍了ASP.NET - AppDomain.CurrentDomain.GetAssemblies() - AppDomain 重启后程序集丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Bootstrapper,它查看 ASP.NET MVC 应用程序中的所有程序集,以查找实现 IBootstrapperTask 接口的类型,然后将它们注册到 IOC Contrainer.这个想法是,您可以将您的 IBootstrapperTasks 放在任何地方,并按照您的喜好组织您的项目.

I have a Bootstrapper that looks through all Assemblies in an ASP.NET MVC application to find types that implement an IBootstrapperTask interface, and then registers them with an IOC Contrainer. The idea is that you can literaly place your IBootstrapperTasks anywhere, and organise your Projects how you please.

引导程序代码:

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
    }
}

在完整构建后,AppDomain.CurrentDomain.GetAssemblies() 返回我的解决方案中的所有程序集(包括所有 GAC 的程序集,但我不介意).

After a full build, AppDomain.CurrentDomain.GetAssemblies() returns all Assemblies in my solution (including all the GAC one's but that doesn't bother me).

但是,如果 AppDomain 重新启动,或者我反弹"Web.Config 文件(添加空间并保存),静态构造函数将再次运行,但是当 AppDomain.CurrentDomain.GetAssemblies() 被调用,大部分程序集都丢失了,包括包含我的 IBootstrapperTask 类型的程序集.

However, if the AppDomain is restarted, or I 'bounce' the Web.Config file (adding a space and saving), the static constructor is run again but when AppDomain.CurrentDomain.GetAssemblies() is called, most of the Assemblies are missing, including the one containing my IBootstrapperTask types.

我该如何解决这个问题?我想我可以 System.IO/bin 目录并手动加载那里的所有 DLL,但如果可能的话宁愿避免这种情况,或者这是唯一的方法?我是否对此采取了正确的一般方法?

How do I get around this problem? I guess I could System.IO the /bin directory and load all the DLLs in there manually, but would rather avoid this if possible, or is that the only way? Am I taking the right general approach to this?

这是一个在 .NET 4.0 上运行的 ASP.NET MVC 2.0 应用程序,我在使用内置的 Visual Studio 2010 Cassini Web 服务器和 Windows Server 2008 上的集成管道模式下的 IIS7.0 时遇到了这个问题.

This is an ASP.NET MVC 2.0 application running on .NET 4.0, I get this problem with the built-in Visual Studio 2010 Cassini web server, and with IIS7.0 in Integrated Pipeline Mode on Windows Server 2008.

我刚刚看到这个 SO 帖子 AppDomain.GetAssemblies 和 BuildManager.GetReferencedAssemblies 之间的区别,这表示 AppDomain 仅在需要时加载程序集(例如,当首次调用该程序集中的方法/类时).我想这可以解释为什么 AppDomain.CurrentDomain.GetAssemblies() 上缺少程序集,因为 Bootstrapper 很早就运行了.

I just came across this SO post Difference between AppDomain.GetAssemblies and BuildManager.GetReferencedAssemblies which says the AppDomain only loads the Assemblies as they're needed (eg. when a method/class from that Assembly is first called). I guess that would explain why the Assemblies are missing on AppDomain.CurrentDomain.GetAssemblies() as the Bootstrapper is run very early on.

我注意到我是否在 Bootstrapper 之前从丢失的程序集中调用了某物",例如:

I noticed if I placed a call to 'something' from the missing Assembly before the Bootstrapper eg:

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

        Bootstrapper.Run();
    }
}

...它似乎解决了问题,但它有点黑客.

...it seems to fix the problem, but it is a bit of a hack.

推荐答案

我查看了 ASP.NET MVC 2.0 源代码并查找了 AreaRegistration.RegisterAllAreas(); 是如何实现的.此行通常放入 Global.asax Application_Start() 方法中,并在内部扫描所有程序集以查找实现 AreaRegistration 抽象类型的类型.这就是我所追求的行为.

I looked through the ASP.NET MVC 2.0 source code and looked up how AreaRegistration.RegisterAllAreas(); is implemented. This line is usually put into the Global.asax Application_Start() method and internally it scans all Assemblies for types that implement the AreaRegistration abstract type. This is kinda the behaviour I'm after.

似乎 RegisterAllAreas() 调用了 BuildManager.GetReferencedAssemblies(),好吧,如果它对 MVC 来说足够好,那么它对我来说就足够了 :-)

It appears RegisterAllAreas() makes a call to BuildManager.GetReferencedAssemblies(), well if it's good enough for MVC then it's good enough for me :-)

我已经做了一些实验,BuildManager.GetReferencedAssemblies() 甚至会选择临时的、随机的 DLL 放到/bin 文件夹中,即使没有引用 Visual Studio 解决方案中的任何项目.所以它看起来比 AppDomain.Current.GetAssemblies() 可靠得多.

I've done some experimentation and BuildManager.GetReferencedAssemblies() will even pick up adhoc, random DLL's dropped into the /bin folder, even with no references to any projects in the Visual Studio solution. So it appears far more reliable than AppDomain.Current.GetAssemblies().

我已将我的程序集定位器代码重写为以下内容:

I've rewritten my Assembly locator code to the following:

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;
    }
}

这篇关于ASP.NET - AppDomain.CurrentDomain.GetAssemblies() - AppDomain 重启后程序集丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆