所以我的场景有点搞笑但是有理由。
我有一个名为Parent的父Web应用程序和一个名为Child的第二个Web应用程序。 Child是IIS7下的IIS7中的虚拟目录,它是IIS中的一个应用程序。 Child不是文件系统中父级的子目录,仅在IIS中作为虚拟目录。在父Web应用程序中的应用程序加载(global_asax中的Application_Start)中,我告诉它使用Assembly.LoadFrom()将其加载到Parent的app域中,从childs bin文件夹加载子web dll。然后,当我尝试访问/Child/Default.aspx时,我收到一条错误消息:
分析程序错误
分析程序错误消息:无法加载类型'Child._Default'。
现在,Child.dll(包含子代码的web dll等)位于父应用程序的应用程序域中,我可以在父页面Default.aspx的代码后面成功地反映它及其成员。
此外,在Child / Default.aspx上,如果我将Inherits =“Child._Default”更改为Inherits =“System.Web.UI.Page”,然后更改为< %%>页面上的标签枚举app域中的dll我可以看到Child.dll并反映其成员并调用函数。
有一件事是在页面指令中将CodeBehind更改为CodeFile。然后页面正确解析。但是,这仅适用于网站采用未编译的非发布形式。
答案 0 :(得分:2)
当appdomain试图解决Child项目中页面的“Child”程序集时,appdomain没有查看它的汇编列表。
您需要做的是在AppDomain中使用AssemblyResolve事件处理程序。你可以这样做:
首先我们创建和AssemblyLoader类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.IO;
namespace Parent
{
internal class AssemblyLoader
{
private static List<AssemblyInformation> virtualDirectoryAssemblies = new List<AssemblyInformation>();
private static readonly string virtualDirectoryBinFolderFormatString = "~/{0}/bin/";
private static readonly string[] pathSplitParams = new string[1] { "\\" };
private static readonly string[] assemblyNameSplitParams = new string[1] { "," };
internal static Assembly AssemblyResolve(object sender, ResolveEventArgs e)
{
var name = e.Name.Split(assemblyNameSplitParams, StringSplitOptions.RemoveEmptyEntries).First();
if (!virtualDirectoryAssemblies.Exists(a => a.Name.Equals(name)))
return null;
return Assembly.LoadFrom(virtualDirectoryAssemblies.Single(a => a.Name.Equals(name)).Path);
}
internal static void LoadVirtualDirectories(List<string> virtualDirectories)
{
foreach (var v in virtualDirectories)
{
var path = HttpContext.Current.Server.MapPath(string.Format(virtualDirectoryBinFolderFormatString, v));
AppDomain.CurrentDomain.AppendPrivatePath(path);
AppDomain.CurrentDomain.SetShadowCopyPath(path);
var assemblies = Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories).ToList();
foreach (var a in assemblies)
{
var name = a.Split(pathSplitParams, StringSplitOptions.RemoveEmptyEntries).Last().Replace(".dll", string.Empty);
if(!virtualDirectoryAssemblies.Exists(i => i.Name.Equals(name)))
{
virtualDirectoryAssemblies.Add(new AssemblyInformation
{
Name = name,
Path = a
});
}
}
}
}
class AssemblyInformation
{
public string Name { get;set; }
public string Path { get; set; }
}
}
}
在Parent项目的web.config文件中,我添加了这个(如果你有更多的虚拟目录,想法是有一个逗号分隔列表):
<appSettings>
<add key="VirtualDirectories" value="Child"/>
</appSettings>
在子项目的web.config中,将此引用添加到程序集子程序集:
<system.web>
<compilation>
<assemblies>
<add assembly="Child, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</assemblies>
</compilation>
</system.web>
它也可以是这样的:
<system.web>
<compilation>
<assemblies>
<add assembly="Child"/>
</assemblies>
</compilation>
</system.web>
现在,最后但并非最不重要的是,我们将其放入Global.asax:
protected void Application_Start(object sender, EventArgs e)
{
AppDomain.CurrentDomain.AssemblyResolve += AssemblyLoader.AssemblyResolve;
var virtualDirectories =
ConfigurationManager.AppSettings.Get("VirtualDirectories").Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList();
AssemblyLoader.LoadVirtualDirectories(virtualDirectories);
}
我们已经完成......:P