52
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)
{
}

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

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

4

5 回答 5

60

当前 AppDomain 上的UnhandledException事件没有触发的原因是服务的执行方式。

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

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

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

于 2011-02-25T13:27:06.010 回答
10

在 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();
}
于 2010-03-26T22:29:43.970 回答
5

当我在自己的 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();
        }
    }
于 2017-08-12T13:34:53.073 回答
4

知道这个线程有点老了,但认为根据个​​人在 .NET 中开发 Windows 服务的经验添加一些评论会很有用。 最好的方法是尽可能避免在服务控制管理器下进行开发——为此你需要一个简单的工具来模拟服务的启动方式——可以创建服务类的实例(你已经从 ServiceBase 派生) ) 并调用您的 OnStart、OnStop 等方法。根据您的需要,此工具可以是控制台应用程序或 Windows 应用程序。

这几乎是我发现在 .NET 中调试服务启动问题的唯一方法——代码、Visual Studio 和真正的服务控制管理器之间的交互只会使该过程变得不可能。

HTH。

于 2010-08-26T10:34:12.630 回答
2

只是好奇,您要完成什么:避免服务崩溃或报告错误?

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

在成功停止服务之前,您还可以将ExitCode属性设置为非零值。如果系统管理员从“服务”控制面板启动您的服务,并且您的服务突然停止并出现非零退出代码,则 Windows 会显示带有错误描述的错误消息。

于 2010-03-16T18:38:43.153 回答