【问题标题】:Why do ASP.NET resolve assembly references differently?为什么 ASP.NET 以不同的方式解析程序集引用?
【发布时间】:2011-08-11 12:13:08
【问题描述】:

我真的很努力地寻找一个类似的问题来获得一些线索,但似乎没有人描述我们遇到的情况,所以就这样吧。

背景

我们的产品具有以下一般设计:

[本地安装文件夹]

  • 包含一组 .NET 程序集,实现了我们的大部分产品功能。
  • 示例:Implementation1.dllImplementation2.dll

[GAC]

  • ClientAPI.dll。我们的客户端程序集,从最终用户 Visual Studio 项目中引用。强烈引用本地安装文件夹中的实现 dll。

在 ClientAPI.dll 中,我们有一个入口点,需要最终用户项目调用。让我们称之为Initialize()

我们在Initialize 中做的第一件事是使用AssemblyResolve 事件在当前域上安装一个所谓的程序集解析处理程序。该处理程序将知道如何定位实现 dll 并将它们加载到客户端进程中,使用 Assembly.Load()

考虑一个控制台应用程序。它看起来像:

class Class1
{
    void Main(string[] args)
    {
        ClientAPI.Initialize();

        // Use other API's in the assembly, possibly internally referencing the
        // implementation classes, that now will be resolved by our assembly
        // resolve handler.
    }
 }

现在,控制台/Windows 窗体/WPF 世界中的一切都很好。我们的程序集解析处理程序已正确安装和调用,一旦 ClientAPI.dll 需要它们的功能,它就可以成功解析对实现 DLL 的引用。

问题陈述

话虽如此,我们不打算只支持控制台或 WPF 应用程序,因此我们依赖 ASP.NET 中的相同设计。因此,在 VS 2010 中创建一个新的 ASP.NET Web 应用程序项目,我们认为一切都会像这样简单:

class Globals : HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        ClientAPI.Initialize();

        // ...
    }
}

在 ASP.NET 运行时世界中停留了 20 到 30 个小时,在开发服务器和 IIS 中尝试了上述内容,我们了解到那里的事情并不像我们预期的那样。

事实证明,在 ASP.NET 中,只要在任何地方引用 ClientAPI 类,它对任何其他程序集的所有引用都会立即解析。不仅如此:结果被缓存(设计上,我们发现了 .NET 2.0),这意味着我们根本没有机会尝试帮助 CLR。​​

如果不进一步详细说明我们尝试和学习的不同事物,基本上可以归结为我们遇到的这个问题:

为什么 ASP.NET 会像这样解析引用?它与其他类型的应用程序如何做到这一点不兼容,更重要的是,它不是根据 .NET/CLR 运行时的文档,指定对外部类型/程序集的引用将在第一次需要时解析(即当首先在代码中使用)。

任何形式的见解/想法都将受到高度赞赏!

【问题讨论】:

  • 好问题。需要一些颠簸。
  • 我最近也遇到了这个问题。这是非常令人沮丧的,没有真正好的解决方案。现在在 ASP.NET 4 中以 PreApplicationStartMethodAttribute 的形式存在一种解决方案,它允许您在 ASP.NET 管道的早期运行代码,从而允许您处理程序集的解析。 NuGet 上可用的 WebActivator 项目利用了这个新属性并对其进行了扩展。当然这只适用于 ASP.NET 4...更多信息可以在这里找到:haacked.com/archive/2010/05/16/…

标签: asp.net gac assembly-references assemblyresolve


【解决方案1】:

Windows 窗体/WPF 应用程序在单个客户端计算机上运行(因此在单个本地上下文中运行),而 ASP.Net 在 IIS、应用程序池、服务器或一组服务器上运行(在网络场中)情况)。加载到应用程序池中的任何内容都可供整个应用程序使用(因此在连接到应用程序的所有客户端之间共享)。

HttpApplication.Application_Start 在应用程序启动时执行一次。它不会像 Winforms 应用程序那样在每个客户端执行 - 如果您需要为每个连接的客户端初始化某些内容,请使用 Session_Start 或 Session_OnStart,但随后您可能会遇到服务器的内存问题,具体取决于有多少客户端将连接到您的 Web 应用程序。这还取决于您的类是否为单例,以及 Initialize() 方法是否为静态。如果您遇到上述任何一种情况,您很快就会遇到跨线程问题。

另外值得注意的是,空闲的 IIS 应用程序池会在一段时间后自行重置。例如,如果没有人在一夜之间使用 Web 应用程序,IIS 将刷新应用程序的应用程序池并释放内存。可以在 IIS 管理中更改这些设置,但在这样做时应该小心 - 更改这些设置以规避设计不当的对象(或不是为 Web 应用程序设计的对象)可能会产生更多问题。

仅供参考 - 我有点挑剔,但为免生疑问,该对象没有缓存 - 是的,它已加载到内存中,但内存的管理方式已完成您如何设计对象(网络世界中的缓存是完全不同的事情,可以在应用程序的许多不同层中实现)。

不要试图让 Web 应用程序像 Windows 应用程序一样运行;你只会给自己制造更多问题!

【讨论】:

    猜你喜欢
    • 2011-05-14
    • 2020-07-03
    • 2016-10-17
    • 1970-01-01
    • 1970-01-01
    • 2019-09-12
    • 1970-01-01
    • 2013-08-25
    • 1970-01-01
    相关资源
    最近更新 更多