![](/img/trans.png)
[英]Is `GetReferencedAssemblies` a subset of `AppDomain.CurrentDomain.GetAssemblies()`?
[英]ASP.NET - AppDomain.CurrentDomain.GetAssemblies() - Assemblies missing after AppDomain restart
我有一個Bootstrapper,它可以查看ASP.NET MVC應用程序中的所有程序集,找到實現IBootstrapperTask
接口的類型,然后使用IOC Contrainer注冊它們。 我們的想法是,您可以隨意將您的IBootstrapperTasks放置在任何地方,並按您喜歡的方式組織您的項目。
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
}
}
完整構建之后, 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 post AppDomain.GetAssemblies和BuildManager.GetReferencedAssemblies之間的區別,它說AppDomain只在需要時加載程序集(例如,當首次調用該程序集中的方法/類時)。 我想這可以解釋為什么AppDomain.CurrentDomain.GetAssemblies()
上缺少程序集,因為Bootstrapper很早就運行了。
我注意到,如果我在Bootstrapper之前調用缺少的Assembly中的'something',例如:
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()
更可靠。
我已將Assembly定位器代碼重寫為以下內容:
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;
}
}
看起來你解決了自己的問題。
編輯:就個人而言,我實際上會逐個枚舉程序集,加載它們並查找接口。 是基於文件而不是AppDomain正在做的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.