C# IIS应用程序池回收和本机程序集

C# IIS应用程序池回收和本机程序集,c#,.net,iis,.net-assembly,C#,.net,Iis,.net Assembly,我有一个在IIS下运行的应用程序,该应用程序有三个程序集:托管程序集、混合程序集和本机dll。 托管程序集公开一个单例对象MaS,该对象通过混合单例MiS(C++/CLI)包装本机单例NaS 问题 当IIS回收应用程序池时,受管的单例MaS似乎消失了,其程序集从APPDOMAIN卸载,混合的MiS也是如此。但是,本机单例NaS仍然存在,不会被破坏。在我的例子中,这是有问题的,因为当应用程序被回收并再次加载时,托管单例(现在是MaS1)会变得混乱,因为它在内存中发现了一个已经存在的本机单例NaS

我有一个在IIS下运行的应用程序,该应用程序有三个程序集:托管程序集、混合程序集和本机dll。 托管程序集公开一个单例对象
MaS
,该对象通过混合单例
MiS
(C++/CLI)包装本机单例
NaS

问题

当IIS回收应用程序池时,受管的单例
MaS
似乎消失了,其程序集从APPDOMAIN卸载,混合的
MiS
也是如此。但是,本机单例
NaS
仍然存在,不会被破坏。在我的例子中,这是有问题的,因为当应用程序被回收并再次加载时,托管单例(现在是
MaS1
)会变得混乱,因为它在内存中发现了一个已经存在的本机单例
NaS

问题


应用程序池回收如何处理本机DLL?它们是否被卸载?

Appdomain回收不会卸载Appdomain,而是加载一个新域,后续请求由一个新Appdomain处理

旧appdomain仅在处理完已接受的请求后卸载

如果旧appdomain在非托管代码中执行阻塞操作,则也可能无法卸载

作为一种解决方法,您可以禁用apppool回收并配置工作进程。 单独的工作进程将确保隔离非托管dll状态

您可以使用以下代码轻松检查非托管dll是否在appdomains之间共享其状态:

托管代码:

[DllImport("Win32Library.dll")]
public static extern Int16 inc();

private readonly static DateTime AppDomainStarted = DateTime.UtcNow;

public ActionResult Counter()
{
    return new JsonResult { Data = new { counter = inc(), appDomainId = AppDomain.CurrentDomain.Id, started = AppDomainStarted.ToString() }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
extern "C" __declspec(dllexport) short inc();

short inc()
{
    static int counter = 0;
    return counter++;
}
非托管代码:

[DllImport("Win32Library.dll")]
public static extern Int16 inc();

private readonly static DateTime AppDomainStarted = DateTime.UtcNow;

public ActionResult Counter()
{
    return new JsonResult { Data = new { counter = inc(), appDomainId = AppDomain.CurrentDomain.Id, started = AppDomainStarted.ToString() }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
extern "C" __declspec(dllexport) short inc();

short inc()
{
    static int counter = 0;
    return counter++;
}

只需重新编译您的aspnet代码并刷新浏览器即可看到计数器中递增的结果,以及工作进程中的appdomain id。确保使用IISExpress进行调试。

我不希望非COM本机对象被神奇地销毁,因为某些技术上不相关的“管理程序集”在AppDomain回收时被卸载。显然,进程内对象将在AppPool(进程)回收时被销毁。。。这与你的观察相矛盾,让我完全困惑…@AlexeiLevenkov完全同意你的观点!我认为将这些邪恶的二进制文件称为程序集是对.NET的不尊重。将更新我的帖子。感谢you@AlexeiLevenkov确切地所有托管对象都将被销毁,本机对象将保留在内存中,不会被销毁:(+1.Hm好的,那么当加载新的应用程序域时,将创建一个新的托管单例,而不使用其本机计数器部分,因为它已经在内存中。这是正确的吗?这些应用程序域共享所有加载的本机对象还是每个应用程序域都有自己的本机对象集?它在工作进程中的所有应用程序域之间共享。您需要E循环工作进程以重新初始化。我想这仅适用于IIS配置为将所有后续应用程序域加载到同一进程中的情况,对吗?默认情况下是这样。您需要检查应用程序池中的可用设置。应用程序域定期循环,工作进程少量生成。通常,工作进程因失败而循环保护理由。