如何在Windows服务中设置.NET UnhandledException处理?

Mik*_*ras 47 c# windows-services exception-handling unhandled-exception

protected override void OnStart(string[] args)
{
    AppDomain.CurrentDomain.UnhandledException +=
        new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

    Thread.Sleep(10000);

    throw new Exception();
}

void CurrentDomain_UnhandledException(object sender,
                                      UnhandledExceptionEventArgs e)
{
}
Run Code Online (Sandbox Code Playgroud)

我在我的Windows服务中将调试器附加到上面的代码,在CurrentDomain_UnhandledException中设置断点,但它从未被命中.弹出的异常是说它未处理,然后服务停止.我甚至尝试在事件处理程序中放入一些代码,以防它被优化掉.

这不是在Windows服务中设置未处理的异常处理的正确方法吗?

Chr*_*son 55

UnhandledException当前AppDomain上的事件未触发的原因是服务的执行方式.

  1. 用户从Windows服务控制管理器(SCM)发送"启动"命令.
  2. 该命令由框架的ServiceBase实现接收并分派给该OnStart方法.
  3. OnStart方法被调用.

抛出的任何异常都OnStart在基类中处理,记录到事件日志中,并转换为返回给SCM的错误状态代码.因此,异常永远不会传播到AppDomain的未处理异常处理程序.

我认为您会发现从您的服务中的工作线程抛出的未处理异常被AppDomain的未处理异常处理程序捕获.


Ian*_*cer 9

在Windows服务中,您不希望在OnStart方法中运行太多代码.您只需要启动服务线程然后返回的代码.

如果这样做,您可以处理服务线程中发生的异常.

例如

public static void Start()
{
    AppDomain currentDomain = AppDomain.CurrentDomain;
    currentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException);

    running = true;
    ThreadStart ts = new ThreadStart(ServiceThreadBody);
    thread = new Thread(ts);
    thread.Name = "ServiceThread";
    thread.Priority = ThreadPriority.BelowNormal;
    thread.Start();
}
Run Code Online (Sandbox Code Playgroud)


小智 6

当我开发自己的 Windows 服务时,它很奇怪地自行停止。我认为这是因为无人处理的异常。目前我正在捕获文本文件上的非手动异常。首先,由于在文本文件上记录注释,您必须在 C 位置创建新文件 ServiceLog.txt。通过下面的编码,我得到了所有未经处理的异常及其行号。

using System.Security.Permissions;
using System.IO;

[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
    protected override void OnStart(string[] args)
    {   AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
        ...
        Your codes...
        ....
    }
    void MyHandler(object sender, UnhandledExceptionEventArgs args)
    {
        Exception e = (Exception)args.ExceptionObject;
        WriteToFile("Simple Service Error on: {0} " + e.Message + e.StackTrace);
    }
    private void WriteToFile(string text)
    {
        string path = "C:\\ServiceLog.txt";
        using (StreamWriter writer = new StreamWriter(path, true))
        {
            writer.WriteLine(string.Format(text, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss tt")));
            writer.Close();
        }
    }
Run Code Online (Sandbox Code Playgroud)


Ste*_*son 5

知道该线程有些陈旧,但认为根据在.NET中开发Windows服务的个人经验来添加一些注释将很有用。 最好的方法是避免尽可能多地在Service Control Manager下进行开发 -为此,您需要一个简单的工具来模拟服务的启动方式-可以创建服务类实例(已从ServiceBase派生的实例)的工具),然后调用您的OnStart,OnStop等方法。根据需要,此工具可以是控制台应用程序或Windows应用程序。

这几乎是我发现的用于调试.NET中服务启动问题的唯一方法-代码,Visual Studio和真实的服务控制管理器之间的交互只会使该过程无法实现。

HTH。

  • +1:在单独的库中实现所有逻辑,然后从服务中调用。从控制台应用程序调用相同的库以进行开发/调试。 (2认同)
  • 我喜欢您的方法,但这不是调试服务启动问题的唯一方法。我要做的事情-特别是在生产环境中调试服务时-将WinDbg设置为:1.在主机进程启动时将其附加到服务上,并2.打开侦听端口(需要克服服务隔离)。然后,可以使用在用户会话下运行的另一个WinDbg实例开始调试。(作为第一条语句对“ RequestAdditionalTime”的可配置调用或注册表配置,有助于克服SCM对服务启动时间的时间限制) (2认同)

Pau*_*ams 2

只是好奇,您想要实现什么目标:避免服务崩溃或报告错误?

对于报告,我认为最好的选择是添加顶级 try/catch 语句。您可以尝试将它们记录到 Windows 事件日志和/或日志文件中。

您还可以将ExitCode属性设置为非零值,直到成功停止服务。如果系统管理员从“服务”控制面板启动您的服务,并且您的服务突然停止并出现非零退出代码,Windows 可能会显示一条错误消息以及错误说明。