修改 web.config 时如何防止 ASP.NET 应用程序重新启动?

Posted

技术标签:

【中文标题】修改 web.config 时如何防止 ASP.NET 应用程序重新启动?【英文标题】:How to prevent an ASP.NET application restarting when the web.config is modified? 【发布时间】:2010-10-11 11:01:50 【问题描述】:

我通过 ApplicationHost.CreateApplicationHost 方法托管 ASP.NET 运行时。当我在应用程序运行时修改web.config 时,我看到很多第一次机会ThreadAbortExceptions 被抛出。这是在我的应用程序崩溃之前。我假设这是因为运行时检测到配置更改并想要重新启动。

这对我们来说并不是一个真正受支持的场景,所以我希望我可以关闭自动重新加载。

有人知道怎么做吗?

【问题讨论】:

【参考方案1】:

据我所知,没有办法禁用此行为,更改 webconfig 会强制重新启动应用程序。

更新:实际上是可以的,有很多方法,有据可查,如explained in this answer*

原答案:

有一个类似的问题here 仅供参考。我发现了可能有用的其他信息。

配置更改导致重启 应用程序域 更改为 Web.config 中的配置设置 文件间接导致应用程序 域重新启动。这种行为 设计发生。您可以选择 使用 configSource 属性 参考外部配置文件 不会导致重新启动时 做出改变。了解更多信息, 参见General Attributes Inherited by Section Elements.中的configSource

来自This MSDN Article

* 免责声明:我写了另一个答案,通常不会进行自我参考,但发现它足够相关,因为在这篇文章发布 8 年后,它确实非常不同:解决方案非常简单通过点击 IIS 前端,从 ASP.NET 1.0 开始就有解决方法。

【讨论】:

如果我错了,请纠正我,但我相信外部配置文件也会重新启动应用程序? 好吧,我猜 MSDN 文章说不会导致应用程序重新启动,但这是否意味着配置设置不会立即加载? 好的,我刚刚做了一些调查,在我的 ASP.NET 3.5 站点上,应用程序池确实 NOT 重新启动,并且更新的设置值 WAS 反映在网页上。但是,我仍然觉得我看到了一个 Web 应用程序,当外部配置文件更改时会重置。也许那个应用有什么特别之处,或者它是旧版本的 ASP.NET。 更改此默认行为非常容易且容易(自 Windows 2003 以来已经如此),see my answer below。 使用 .Net 4+,我们无法通过修改外部配置文件来始终如一地让 AppDomain 重新启动【参考方案2】:

我遇到了一个更大的问题 - 对 AppDomain 基本目录中的 any 文件或子文件夹的更改会导致托管环境关闭。这对我们的应用程序来说是一个相当大的问题,因为我们在同一个 AppDomain 中运行 WPF UI,我们无法重新启动它而不会对用户造成干扰。

我真的很想避免为应用程序的基于 Web 的部分运行单独的 AppDomain,所以我使用 Reflector 进行了一些挖掘。我发现罪魁祸首是内部类FileChangesMonitor

所以我写了一个可怕的反射黑客来解决这个问题。我想我会把它贴在这里作为其他有同样问题的人的潜在解决方案。您只需要调用HttpInternals.StopFileMonitoring() 来禁用关闭文件/文件夹更改。

internal static class HttpInternals

    private static readonly FieldInfo s_TheRuntime = typeof(HttpRuntime).GetField("_theRuntime", BindingFlags.NonPublic | BindingFlags.Static);

    private static readonly FieldInfo s_FileChangesMonitor = typeof(HttpRuntime).GetField("_fcm", BindingFlags.NonPublic | BindingFlags.Instance);
    private static readonly MethodInfo s_FileChangesMonitorStop = s_FileChangesMonitor.FieldType.GetMethod("Stop", BindingFlags.NonPublic | BindingFlags.Instance);

    private static object HttpRuntime
    
        get
        
            return s_TheRuntime.GetValue(null);
        
    

    private static object FileChangesMonitor
    
        get
        
            return s_FileChangesMonitor.GetValue(HttpRuntime);
        
    

    public static void StopFileMonitoring()
    
        s_FileChangesMonitorStop.Invoke(FileChangesMonitor, null);
    

【讨论】:

但是 appDomains 旨在反映您知道的应用程序域 - WPF 和 Web 之间明显不同的东西。您使用对象的方式不是它不打算使用的。 确实如此,我也确实考虑过使用多个 AppDomain 的利弊。我最终得出结论,运行多个 AppDomain 会比这种方法增加应用程序的复杂性。我很想听听关于这个问题的更多意见。 @Jacob Stanley:首先感谢这个解决方案。我只有一个问题,如何恢复文件监控?例如,手动更新一些 dll 文件后,我想恢复正常的网站行为。 这可能要复杂得多 :) 如果您对 Reflector 感到满意,您可以看到 System.Web.FileChangesMonitor.Stop() 的作用,或许可以尝试反转它。看起来 ASP.NET 通常只在关闭时使用 Stop() 方法。 FileChangesMonitor 上有一些称为 StartListeningToLocalResourceDirectory 的方法和一些看起来很有希望的其他 Start* 方法。如果您能弄清楚 HttpRuntime 类是如何初始化 FileChangesMonitor 的,那么您就走在了正确的轨道上。听起来比我最初做的还要狡猾! :) @Jacob Stanley:是的,这很狡猾,我正在尝试更新正在运行的预编译网站的单个功能。使用 Reflector 和 Reflexil 来实现:)【参考方案3】:

解决方案是将以下元素添加到 web.config 部分:

<httpRuntime
    waitChangeNotification="315360000"
    maxWaitChangeNotification="315360000"
/>

【讨论】:

但这在 IIS7 中不太适用,遗憾的是:forums.iis.net/t/…(虽然我刚刚意识到发帖人没有使用 IIS,所以在这种情况下没关系) 我发现这个答案非常有用,因为其他原因,当您尝试一次更新 10 个文件时,但您不希望 10 个应用程序池回收。此设置将允许您将一堆更新的文件合并到一个重置中。当然,需要更低的数字才能使其有用。 事实上,确实如此。但仅适用于 BIN 文件夹。 web.config 仍然会导致立即回收:beweb.pbworks.com/w/page/30073098/…【参考方案4】:

正如 jfburdet 所述,解决方案是使用 waitChangeNotification 和 maxWaitChangeNotification。

话虽如此,如果 ASP.NET 在混合模式下运行,您应该知道它们无法在 IIS 7 上运行:http://forums.iis.net/t/1149344.aspx

【讨论】:

实际上它确实有效。但仅对于 BIN 文件夹,web.config 仍会导致立即回收。在这篇文章中检查大约三分之一:beweb.pbworks.com/w/page/30073098/…【参考方案5】:

其实前两个答案是错误的。 可能的,并且很容易防止这种回收发生,并且至少从 IIS6 开始,此功能就已可用。

方法 1(系统范围)

HKLM\SOFTWARE\Wow6432Node\Microsoft\ASP.NET\FCNModeDWORD 注册表设置更改为值1,这将禁用所有文件更改通知。

不要被位置弄糊涂了:Wow6432Node 在这种情况下不会影响您的 Web 应用程序的位数。

方法 2 (.NET 4.5+)

如果您使用的是 .NET 4.5,那么 it is now possible to disable this on a per-site level,只需在您的 web.config 中使用以下内容:

<httpRuntime fcnMode="Disabled"/> 

方法 3 (IIS6+)

最后,并且(至少)自 IIS6 以来,there's a setting called DisallowRotationOnConfigChange 仅作为应用程序池的设置(至少这是我认为 MSDN 上的文字试图说的,但我还没有测试过) .将其设置为true,对应用程序池配置的更改不会导致立即回收。

最后一个设置也可以从应用程序池的高级设置中设置:

方法 4(ASP.NET 1.0 和 1.1)

对于使用 ASP.NET 1.0 或 1.1 的(旧)网站,there is a confirmed bug 可能会导致文件更改快速重复回收。当时的解决方法类似于MartinHN 在主要问题下建议的内容,即您的web.config 中的以下内容:

<compilation 
   debug="false"
   defaultLanguage="vb"
   numRecompilesBeforeAppRestart="5000">

这不会禁用回收,但只有在 5000 次重新编译后才会这样做。这个数字是否有用取决于您的应用程序的大小。微软没有明确说明重新编译到底是什么。但是,默认值为 15

顺便说一句: 无论 .NET 或 Windows 的版本如何,我们发现当应用程序从共享运行并在负载平衡的环境中使用时,该站点会不断回收。解决此问题的唯一方法是将 FNCMode 设置添加到注册表(但现在有更多细粒度的选项)。

【讨论】:

我认为方法 2 可能是现在要走的路。我不确定方法 3,是否可以通过 web.config 设置它是否会阻止重新加载所有文件更改?请注意,这不是通过 IIS 运行的,它是托管在 WPF 应用程序中的 ASP.NET AppDomain。方法 1 并不是一个真正的选择,因为它会影响其他应用程序。 @JacobStanley:如果您使用新的 AppDomain 并在同一个 AppPool 中运行它,那么无论您是在 AppPool 设置(方法 3)中设置它还是通过更改 @987654340 @ 在web.config 中(方法2)。同一个站点的 web.config 可以被多个 AppPools 使用,尽管更常见的是同一个 AppPool 用于多个站点,在这种情况下,最好将方法 2 与 fcnMode 一起使用(更好的每个站点粒度)。请注意,您甚至可以通过在其中添加web.config 来为一个站点中的单独目录设置fcnMode @JacobStanley:关于您的另一个问题,disallowRotationOnConfigChange 可以在ApplicationHost.config 文件中设置,但取决于您对生产服务器的访问级别,这可能会或可能不会直接访问。但是,该链接显示了有关如何使用 C# 更改这些设置的代码示例。 @Abel 实际上DisallowRotationOnConfigChange 设置对 web.config 中的更改无效,但仅在应用程序池的设置中有效。请参阅this thread 了解更多信息。 我在 Windows Server 2016 上尝试过方法 1、2 和 3,但即使结合所有 3 种方法,对 web.config 或 applicationHost.config 的任何更改都会导致回收。您能否确认这些方法应该适用于 Windows Server 2016?

以上是关于修改 web.config 时如何防止 ASP.NET 应用程序重新启动?的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 IIS 默认站点 web.config 文件被虚拟目录继承?

ASP.NET和ASP.NETCore多环境配置对比

web。config中如何修改sessionstate 模式设置

如何修改Web.Config里面的值

web站点和windows服务项目发布时如何排除指定文件

如何在复制/粘贴web.config XML节点后阻止自动回车(换行)?