【问题标题】:AssemblyResolve event is not firing during compilation of a dynamic assembly for an aspx page在为 aspx 页面编译动态程序集期间未触发 AssemblyResolve 事件
【发布时间】:2010-05-16 00:33:56
【问题描述】:

这个真的让我很生气。如下:

我的目标是在运行时加载包含嵌入式 aspx、ascx 等的程序集。我还希望不要将程序集文件锁定在磁盘上,这样我就可以在运行时更新它而无需重新启动应用程序(我知道这将保留以前的版本)。

为此,我编写了一个虚拟路径提供程序来解决问题。我已订阅 CurrentDomain.AssemblyResolve 事件,以便将框架重定向到我的程序集。

问题在于,当框架尝试为 aspx 页面编译动态程序集时,我得到以下信息:

编译器错误消息:CS0400:在全局命名空间中找不到类型或命名空间名称“Pages”(您是否缺少程序集引用?)

来源错误: 公共类 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 页面? lede 似乎被埋葬了。
  • 问题是为什么在 aspx 页面的编译期间没有触发 AssemblyResolve 事件。有解决办法吗?

标签: c# reflection assemblies loading


【解决方案1】:

我不确定是什么原因导致缺少程序集引用,但如果我们稍微退后一步,让您的程序按预期工作,那么我们必须解决另一个问题。这个问题是加载程序集的锁定。 .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( 也会返回相同的程序集 oO
【解决方案2】:

我认为我可以通过以下方式使用它:

 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 页面的标记和代码隐藏,它按预期工作。

总结一下:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    相关资源
    最近更新 更多