我真的很努力找到一个类似的问题来获得一些线索,但似乎没有人描述我们所拥有的案例,所以就这样了。
背景
我们的产品具有以下一般设计:
[本地安装文件夹]
[GAC]
在ClientAPI.dll中,我们有一个入口点,我们需要调用最终用户项目。让我们称之为Initialize()
。
我们在Initialize
中做的第一件事就是使用AssemblyResolve
事件在当前域上安装所谓的程序集解析处理程序。该处理程序将知道如何使用Assembly.Load()
找到实现dll并将它们加载到客户端进程中。
考虑一个控制台应用程序。它看起来像:
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运行时的文档,指定在首次需要时解析对外部类型/程序集的引用(即首先在代码中使用。)
任何形式的见解/想法都将受到高度赞赏!
答案 0 :(得分:0)
Windows窗体/ WPF应用程序在单个客户端计算机上运行(因此在单个本地上下文中运行),而ASP.Net在IIS,应用程序池,服务器或服务器集(在Web场中)中运行情况)。应用程序池中加载的内容可供整个应用程序使用(因此在连接到应用程序的所有客户端之间共享)。
当应用程序启动时,HttpApplication.Application_Start执行一次。它不像Winforms应用程序那样在每个客户端执行 - 如果你需要为每个连接的客户端初始化一些东西,使用Session_Start或Session_OnStart,但是你可能会遇到服务器的内存问题,具体取决于客户端数量将要连接到您的Web应用程序。这还取决于您的类是否为单例,以及Initialize()方法是否为静态。如果您遇到这些情况中的任何一种,那么您将很快遇到交叉线程问题。
此外,值得注意的是,空闲的IIS应用程序池将在一段时间后自行重置。例如,如果没有人在一夜之间使用Web应用程序,IIS将刷新应用程序的应用程序池并释放内存。这些设置可以在IIS管理中进行更改,但在执行此操作时应该小心 - 更改这些设置以绕过设计不当的对象(或者不是为Web应用程序设计的对象)可能会产生更多问题。
仅供参考 - 我有点挑剔,但为了避免疑问,该对象不缓存 - 是的,它被加载到内存中,但是如何管理内存如何设计对象(在Web世界中缓存是完全不同的事情,可以在应用程序的许多不同层中实现)。
不要试图使Web应用程序像Windows应用程序一样;你只会给自己制造更多问题!