分析器错误:无法从IIS7中的虚拟目录中的appdomain加载类型“x”

时间:2010-08-04 16:40:24

标签: asp.net iis-7 appdomain

所以我的场景有点搞笑但是有理由。

我有一个名为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。然后页面正确解析。但是,这仅适用于网站采用未编译的非发布形式。

1 个答案:

答案 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