好的,经过大量调试后,我已经可以正常工作了!事实证明,我的库项目是针对 Asp.Net MVC 4.0 编译的,即使 Nuget 和属性窗口声称是 5.1。 Nuget/MS 再次失败。我的库反映的 Asp.Net MVC 应用程序正在使用 MVC 5.1,因此当Assembly.LoadFrom 和AssemblyResolve 事件运行时,它会将System.Web.Mvc.dll 的两个版本加载到LoadFrom 上下文(4.0 和5.1)中,并且这导致 IsSubclassOf() 方法在预期结果应该为 true 时返回 false。
我在调试时在上面的 cmets 中提到的非常奇怪的错误:The type 'System.Web.Mvc.AreaRegistration' exists in both 'System.Web.Mvc.dll' and 'System.Web.Mvc.dll' 现在才有意义,但只有在事后才有意义。
我最终追踪到这一点的方法是写出AssemblyResolve 被要求解决的所有程序集,并注意到System.Web.Mvc.dll 不在列表中。我启动了Assembly Binding Log Viewer 并清楚地看到System.Web.Mvc.dll 被加载了两次。
回想起来,应该跳过所有自定义日志记录并使用程序集绑定日志查看器来验证每个程序集仅加载一个,并且它是您期望的正确版本。
弄清楚如何正确使用AssemblyResolve 是一场噩梦,所以这是我未完成但为后代工作的代码。
public class CodeGenerator
{
public static string BaseDirectory { get; set; }
public static string BinDirectory { get; set; }
static CodeGenerator()
{
BinDirectory = "bin";
// setting this in a static constructor is best practice
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
public CodeGenerator(string entryAssemblyPath = null, string baseDirectory = null, string binDirectory = null)
{
if (string.IsNullOrWhiteSpace(baseDirectory))
BaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
else
BaseDirectory = baseDirectory;
if (string.IsNullOrWhiteSpace(binDirectory) == false)
BinDirectory = binDirectory;
if (entryAssemblyPath == null) // running under the Asp.Net domain
EntryAssembly = GetWebEntryAssembly(); // get the Asp.Net main assembly
else
{
// manually load the assembly into the domain via a file path
// e:\inetpub\wwwroot\myAspNetMVCApp\bin\myApp.dll
EntryAssembly = Assembly.LoadFrom(entryAssemblyPath);
}
var areas = GetAreaRegistrations(); // reflect away!
... code ...
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
if (args == null || string.IsNullOrWhiteSpace(args.Name))
{
Logger.WriteLine("cannot determine assembly name!", Logger.LogType.Debug);
return null;
}
AssemblyName assemblyNameToLookFor = new AssemblyName(args.Name);
Logger.WriteLine("FullName is {0}", Logger.LogType.Debug, assemblyNameToLookFor.FullName);
// don't load the same assembly twice!
var domainAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var skipLoading = false;
foreach (var dAssembly in domainAssemblies)
{
if (dAssembly.FullName.Equals(assemblyNameToLookFor.FullName))
{
skipLoading = true;
Logger.WriteLine("skipping {0} because its already loaded into the domain", Logger.LogType.Error, assemblyNameToLookFor.FullName);
break;
}
}
if (skipLoading == false)
{
var requestedFilePath = Path.Combine(Path.Combine(BaseDirectory, BinDirectory), assemblyNameToLookFor.Name + ".dll");
Logger.WriteLine("looking for {0}...", Logger.LogType.Warning, requestedFilePath);
if (File.Exists(requestedFilePath))
{
try
{
Assembly assembly = Assembly.LoadFrom(requestedFilePath);
if (assembly != null)
Logger.WriteLine("loaded {0} successfully!", Logger.LogType.Success, requestedFilePath);
// todo: write an else to handle load failure and search various probe paths in a loop
return assembly;
}
catch (FileNotFoundException)
{
Logger.WriteLine("failed to load {0}", Logger.LogType.Error, requestedFilePath);
}
}
else
{
try
{
// ugh, hard-coding, but I need to get on with the real programming for now
var refedAssembliesPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1");
requestedFilePath = Path.Combine(refedAssembliesPath, assemblyNameToLookFor.Name + ".dll");
Logger.WriteLine("looking for {0}...", Logger.LogType.Warning, requestedFilePath);
Assembly assembly = Assembly.LoadFrom(requestedFilePath);
if (assembly != null)
Logger.WriteLine("loaded {0} successfully!", Logger.LogType.Success, requestedFilePath);
// todo: write an else to handle load failure and search various probe paths in a loop
return assembly;
}
catch (FileNotFoundException)
{
Logger.WriteLine("failed to load {0}", Logger.LogType.Error, requestedFilePath);
}
}
}
}
catch (Exception e)
{
Logger.WriteLine("exception {0}", Logger.LogType.Error, e.Message);
}
return null;
}
}