【问题标题】:How to listen to IIS shutdown event in ASP.NET如何在 ASP.NET 中监听 IIS 关闭事件
【发布时间】:2011-06-11 01:10:30
【问题描述】:

我的 ASP.NET 静态变量中有每次插入 X 次时都会将自身刷新到 DB 中。 问题是,如果我发布应用程序,IIS 进程会被我所有的静态材料杀死。

如何保存它 - 或者如何在 ASP.NET 应用程序关闭后刷新它?

谢谢

【问题讨论】:

    标签: c# asp.net iis


    【解决方案1】:

    全球.asax

    void Application_End(object sender, EventArgs e) 
        {
            //  SHUTDOWN CODE HERE
        }
    

    【讨论】:

      【解决方案2】:

      如前所述,强烈建议不要在Application_End 期间让应用程序持久化大数据,因为这可能会在应用程序池关闭时触发,而不是在其关闭开始时触发。这在here 有更详细的解释(但仍然很短)。

      如果仍然想在所有不会立即杀死它的情况下捕获应用程序池的关闭,可以执行以下操作:

      肮脏的方式

      1)获取关机时间限制-IIS管理器->应用程序池->->高级设置...->进程模型组->关机时间限制(秒)

      2) 在应用程序中创建一个线程/任务,使其运行频率是关闭时间限制的两倍,以确保可以捕获“关闭”状态。这个帖子应该

      i) 检查应用程序池是否正在关闭

      public bool IsShuttingDown()
      {
          return System.Web.Hosting.HostingEnvironment.ShutdownReason != ApplicationShutdownReason.None;
      }
      

      ii) 如果正在关闭,请执行您的操作。确保东西只执行一次

      更正确的方式(如here所示)

      1) 创建一个实现IRegisteredObject的类

      public class HostingEnvironmentRegisteredObject : IRegisteredObject
      {
          // this is called both when shutting down starts and when it ends
          public void Stop(bool immediate)
          {
              if (immediate)
                  return;
      
              // shutting down code here
              // there will about Shutting down time limit seconds to do the work
          }
      }
      

      2) 注册您的对象 (Global.asax.cs)

      protected void Application_Start()
      {
          // other initialization code here
      
          HostingEnvironment.RegisterObject(new HostingEnvironmentRegisteredObject());
      }
      

      3) 注销 (source)

      首先调用 Stop 方法,并将立即参数设置为 错误的。对象既可以完成处理,调用 UnregisterObject 方法,然后返回或者可以立即返回 并在调用之前异步完成处理 UnregisterObject 方法。

      如果注册对象在 应用程序管理器的超时期限到期,Stop 方法为 在立即参数设置为 true 的情况下再次调用。当。。。的时候 immediate 参数为 true,注册的对象必须调用 在返回之前取消注册对象方法; 否则,它的 应用程序管理员将删除注册。


      作为附注,我还将介绍一些有关在 ASP.NET Core 2.x 中实现相同思想的细节。这可以使用IApplicationLifetime 接口执行。示例(Startup.cs):

      public void Configure(IApplicationLifetime lifetime)
      {
          var quartz = new JobScheduler(Kernel);
          lifetime.ApplicationStarted.Register(quartz.Start);
          lifetime.ApplicationStopping.Register(quartz.Stop);
      }
      

      注意:这仅在 IIS(可能的其他 Web 服务器)中托管时有效,但在 IISExpress 中无效,它不会触发IApplicationLifetime 功能。

      【讨论】:

      • 感谢您对 IRegisteredObject 的引用!但我发现“立即”标志的意思是“真表示注册的对象应该从托管环境中注销”。所以我认为最好在返回之前进行一些检查并执行 HostingEnvironment.UnregisterObject()。
      • @vladimirkhozeyev - 实际上the documentation 说:“当立即参数为真时,注册对象必须在返回之前调用 UnregisterObject 方法;否则,它的注册将被应用程序管理器删除”。如果我理解正确,忘记注销应该不是问题,因为无论如何 IIS 都应该介入并注销它。
      【解决方案3】:

      依靠应用程序关闭事件来保持数据库更新是有风险的。如果 IIS 被强制重启、回收或断电,那么您将错过该事件。

      【讨论】:

      • 是的,这些情况我无法控制。我想控制我所知道和拥有的......
      • 如果您不在乎错过这些边缘情况,那么您可能不会费心处理优雅的应用程序关闭。让它成为你的应用假设的一部分
      • 更“常见的边缘情况”是关心 graceful 关闭,例如。刷新日志记录,没有意外的.. 应用程序池可以相当频繁地回收(对于具有许多池的大型环境,这意味着可能会丢失许多“常见边缘情况”事件)。
      【解决方案4】:

      您可能不会收到任何有关 IIS 正在关闭的通知。想想如果 IIS AppPool 崩溃会发生什么,或者如果服务器只是断电会发生什么。

      您不能依赖听说过关机事件。如果 IIS 想要关闭,它不一定会通知您的应用程序。我建议您重新考虑您的写入缓冲/缓存方案 - 仅将您可以承受丢失的数据保留在内存中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-10-20
        • 2018-09-12
        • 2021-08-23
        • 1970-01-01
        • 1970-01-01
        • 2021-03-14
        • 2017-03-30
        相关资源
        最近更新 更多