编译动态程序集时,对于一个aspx页面,AssemblyResolve事件未触发。

3
这个问题真的让我很烦。以下是要解决的问题:
我的目标是在运行时加载包含嵌入式aspx、ascx等的程序集。我还希望不锁定磁盘上的程序集文件,这样我就可以在运行时更新它而无需重新启动应用程序(我知道这将保留先前版本的程序集)。
为此,我编写了一个虚拟路径提供程序来完成这项任务。我已经订阅了CurrentDomain.AssemblyResolve事件,以便将框架重定向到我的程序集。
问题在于,当框架尝试为aspx页面编译动态程序集时,我会收到以下错误消息:
编译器错误消息:CS0400:全局命名空间中找不到“Pages”类型或命名空间名称(是否缺少程序集引用?)
源代码错误: public class app_resource_pages__version_1_0_0_0__culture_neutral__publickeytoken_null_default_aspx:global :: Pages._Default,System.Web.SessionState.IRequiresSessionState,System.Web.IHttpHandle 我注意到,如果我使用Assembly.Load(AssemblyName)或Assembly.LoadFrom(filename)加载程序集,则不会出现上述错误。如果我使用Assembly.Load(byte[])(以便不锁定它),则会抛出异常,但是我的AssemblyResolve处理程序在被调用时正确返回程序集(它被调用一次)。
因此,我猜测它在框架解析asp标记时调用一次,但在尝试为aspx页面创建动态程序集时不会调用。

这里的实际问题是什么?如何以非锁定、非阻塞方式加载新的.aspx页面?Led似乎被埋藏了。 - Dan Davies Brackett
问题是为什么在编译aspx页面时AssemblyResolve事件没有触发。有没有解决方法? - John
2个回答

4
我不确定是什么原因导致了缺少程序集引用,但如果我们退后一步,回到您的程序按预期工作的点,那么我们需要解决一个不同的问题。这个问题是加载程序集时的锁定。.Net框架总是锁定已加载的程序集。你能够更新bin文件夹内的dll文件的原因实际上是一个技巧。你看,AppDomain有一个很好的属性叫做ShadowCopyDirectories,它规定了在加载程序集时将要复制的目录。因此,通过改变影子复制目录列表,你可以从任何文件夹加载而不锁定你的程序集:
    protected const string ApplicationAssembliesFolder = "~/Assemblies";

    protected void Application_Start(object sender, EventArgs e)
    {
        var assembliesPath = Server.MapPath(ApplicationAssembliesFolder);

        AppDomain.CurrentDomain.SetShadowCopyPath(
            AppDomain.CurrentDomain.SetupInformation.ShadowCopyDirectories + 
            Path.PathSeparator + assembliesPath);

        Assembly.LoadFrom(
            Path.Combine(assembliesPath, "Example.dll"));
    }

是的,设置shadowcopypath确实可以防止框架锁定磁盘上的文件,但是...即使磁盘上的文件不存在,后续对Assembly.LoadFrom()的调用仍会返回相同的程序集。 - John

1

我认为我已经用以下方法使其工作:

 public Assembly GetAssembly()
    {
        Assembly result = cache.Get(assemblyKey) as Assembly;

        if (result == null)
        {
            lock (this)
            {
                result = cache.Get(assemblyKey) as Assembly;
                if (result == null)
                {
                    assemblyName = System.Reflection.AssemblyName.GetAssemblyName(assemblyFile);
                    result = Assembly.Load(assemblyName);
                    cache.Add(assemblyKey, result, new CacheDependency(assemblyFile), Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.High, new CacheItemRemovedCallback(OnAssemblyRemoved));
                }
            }
        }
        return result;
    }

这仅在新程序集与旧程序集具有不同版本时才有效,这有点合理。应用程序不会重新启动,但会加载新程序集。我尝试更新aspx页面和codebehind的标记,并且按预期工作。

总结:

  1. AppDomain.CurrentDomain.SetShadowCopyPath
  2. Assembly.Load(AssemblyName.GetAssemblyName(assemblyFile))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接