6

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

背景

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

[本地安装文件夹]

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

[广汽]

  • 客户端API.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 运行时的文档,指定对外部类型/程序集的引用将在第一次需要时解析(即当首先在代码中使用)。

任何形式的见解/想法将不胜感激!

4

1 回答 1

0

Windows Forms / WPF applications run on individual client machines (and therefore run in a single, local context), whereas ASP.Net runs within IIS, within an application pool, on a server or set of servers (in a web farm situation). Whatever is loaded in to the application pool is available to the entire application (and therefore is shared between all clients who connect to the application).

HttpApplication.Application_Start is executed once, when the application starts up. It is not executed per client as it would be with a Winforms application - if you need to initialize something for every client that connects, use Session_Start or Session_OnStart, but then you may run in to memory issues with the server, depending on how many clients are going to connect to your web application. This also depends on whether your class is a singleton, and if the Initialize() method is static. If you have either of those situations, you're going to run in to cross-threading problems fairly quickly.

Additionally, it's worth noting that an idle IIS application pool will reset itself after a period of time. If no one uses the web application overnight, for example, IIS will flush the application's application pool and free up memory. These settings can be changed within IIS administration, but you should be careful when doing so - changing these settings to circumvent a badly designed object (or an object that isn't designed for a web application) can create even more problems.

FYI - I'm being a little fussy, but for the avoidance of doubt, the object is not cached - yes, it is loaded in to memory, but how the memory is managed is up to how you've designed the object (caching in the web world is an entirely different thing, and can be implemented in many different layers of your application).

Don't try and make a web application act like a windows application; you'll just create yourself more problems!

于 2012-02-10T13:57:06.347 回答