gpt4 book ai didi

c# - ASP.NET - AppDomain.CurrentDomain.GetAssemblies() - AppDomain 重启后程序集丢失

转载 作者:IT王子 更新时间:2023-10-29 04:11:02 29 4
gpt4 key购买 nike

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

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

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

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

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


编辑: 我刚刚看到这篇 SO 帖子 Difference between AppDomain.GetAssemblies and BuildManager.GetReferencedAssemblies这表示 AppDomain 仅在需要时加载程序集(例如,当首次调用该程序集的方法/类时)。我想这可以解释为什么程序集在 AppDomain.CurrentDomain.GetAssemblies() 上丢失,因为 Bootstrapper 很早就运行了。

我注意到我是否在 Bootstrapper 之前调用了缺少的程序集中的“某物”,例如:

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(); 是如何实现的。此行通常放入 Global.asax Application_Start() 方法,并在内部扫描所有程序集以查找实现 AreaRegistration 抽象类型的类型。这有点像我所追求的行为。

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

我已经做了一些实验,BuildManager.GetReferencedAssemblies() 甚至会选择临时的随机 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;
}
}

关于c# - ASP.NET - AppDomain.CurrentDomain.GetAssemblies() - AppDomain 重启后程序集丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3552223/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com