我有一个 bootstrap 程序,可以查看ASP中的所有程序集.NET MVC应用程序来查找实现IBootstrapperTask接口的类型,然后将它们注册到IOC Contrainer.这个 idea 是,你可以把你的iBootTrapper任务放在任何地方,并随心所欲地组织你的项目.

bootstrap 程序代码:

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 one的程序集,但这并不影响我).

但是,如果AppDomain重新启动,或者我"跳转"了Web.配置文件(添加一个空格并保存),静态构造函数会再次运行,但当调用AppDomain.CurrentDomain.GetAssemblies()时,会运行most of the Assemblies are missing,包括包含我的ibootstrapper任务类型的构造函数.

我怎么才能绕过这个问题呢?我想我可以对/bin目录执行System.IO操作,然后手动加载其中的所有DLL,但如果可能的话,我宁愿避免这样做,或者这是唯一的方法吗?我对这件事采取的总体方法是正确的吗?

这是一个运行在.NET4.0上的ASP.NETMVC2.0应用程序,我在内置的Visual Studio2010Cassini Web服务器和Windows Server2008的集成管道模式下的IIS7.0中遇到了这个问题.


Edit:我刚刚遇到过这样的帖子Difference between AppDomain.GetAssemblies and BuildManager.GetReferencedAssemblies,它说AppDomain只在需要时加载程序集(例如,当第一次调用该程序集中的方法/类时).我想这可以解释为什么AppDomain.CurrentDomain.GetAssemblies()上没有程序集,因为 bootstrap 程序很早就运行了.

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

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

        Bootstrapper.Run();
    }
}

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

推荐答案

我浏览了ASP.NET MVC 2.0源代码,并查看了AreaRegistration.RegisterAllAreas();是如何实现的.这条线通常放在全局.asax Application_Start()方法,并在内部扫描所有程序集,查找实现AreaRegistration抽象类型的类型.这就是我想要的行为.

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

我已经做了一些实验和BuildManager.GetReferenceAssemblys()甚至会拾取临时的、随机的DLL,这些DLL被放入/bin文件夹,即使在Visual Studio解决方案中没有任何项目的引用.因此,它似乎比AppDomain.Current.GetAssemblies()更可靠.

我已将我的装配定位器代码改写为以下内容:

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相关问答推荐

指定的 CGI 应用程序遇到错误,服务器终止了进程

ASP.NET 平台是否有与 Heroku 等价的工具?

无法获取项目引用的依赖项

ASP.NET-MVC 中的表单发布上的 FormCollection 为空

ASP.NET IIS - 请求何时排队?

ASP.NET URL 重写

为什么 Asp.Net Identity IdentityDbContext 是一个黑盒?

在 Asp.net mvc5 中使用用户名而不是邮箱作为身份

ASP.NET Core 2.0 为同一端点结合了 Cookie 和承载授权

如何在 asp net core api 中使用 Created(或 CreatedAtAction / CreatedAtRoute)

解析器错误消息:无法加载类型网络营销

Web API 必填参数

.NET 4.0 中的自定义 MembershipProvider

System.Reflection.Assembly.LoadFile 锁定文件

避免将重复元素添加到列表 C#

如何使用 encodeURIComponent() 解码在 JS 中编码的 HTML?

如何在 ASP.Net MVC 3 中返回 HttpNotFound() 的视图?

ASP.net 判断页面是 http 还是 https

配置授权服务器端点

在 ASP.NET 中使用 SecureString 有什么好处吗?