首页 > 解决方案 > 备份捕获 EventHandler 中抛出的异常

问题描述

我有一个 C# 程序作为 Windows 服务运行,做一些网络恶作剧,我以为我已经设置了最后的“日志致命错误”处理设置。但是我遇到了一个边缘情况,服务最终死了,但躲过了那些捕获。:(

我相信这是由于代码在注册到 .NET 库事件的 EventHandler 中引发异常所致。

显然我可以(并且应该!)在我的处理程序中捕获异常,但我想了解这是如何避免我的后备错误处理,以及我是否可以添加一些更强大的后备日志记录,以确保我有一些日志记录来分析未来类似的静默错误。


相关代码的妙语并不十分复杂:

ServiceBase.Run(container.Resolve<MyProjectWindowsService>());in a try ...catchinProgram.Main() MyProjectWindowsService : ServiceBase是具有实现的服务对象OnStop()NetworkChange.NetworkAvailabilityChanged += CodeThatThrows;

但是当那个异常被抛出时,触发器OnStop()也不是。try...catch我可以在调试器中得到它,它似乎没有任何地方..它只是......停止。

如果需要,请参阅下面的更详细的程序详细信息。

如何在注册到外部库事件的事件处理程序中捕获和记录未处理的异常?

(另外......我在上面描述的行为是预期的行为,还是发生了一些奇怪的事情?)


程序EXE入口点:

using System;
using System.ServiceProcess;
using Autofac;
using Autofac.Extras.NLog;
using NLog;

namespace MyProject.Service
{
    internal static class Program
    {
        private static readonly ILogger Logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        ///     The main entry point for the application.
        /// </summary>
        private static void Main()
        {
            try
            {
                // var container = ...DI Setup...
                ServiceBase.Run(container.Resolve<MyProjectWindowsService>());
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Unexpected error");
            }
            finally
            {
                Logger.Info("==========================");
                Logger.Info("WindowsService Stopped (2)");
                Logger.Info("==========================");
            }

        }
    }
}

服务对象

using System;
using System.ServiceModel;
using System.ServiceProcess;
using Autofac;
using Autofac.Integration.Wcf;
using NLog;

namespace MyProject.Service
{
    public class MyProjectWindowsService : ServiceBase
    {
        private readonly ILogger _logger;

        public DNSProxyWindowsService(ILogger logger)
        {
            ServiceName = Constants.SERVICE_NAME;
            _logger = logger;
        }

        protected override void OnStart(string[] args)
        {
            _logger.Info("==============================");
            _logger.Info("DNProxy WindowsService Started");
            _logger.Info("==============================");

            //Other Active setupsteps
        }

        protected override void OnStop()
        {
            try
            {
                //Other Active shutdown steps.
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Could not shut down service tidily");
            }
            finally
            {
                _logger.Info("==========================");
                _logger.Info("WindowsService Stopped (1)");
                _logger.Info("==========================");
            }
        }
    }
}

EventListener 注册到并最终调用:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using NLog;
using Exception = System.Exception;

namespace DNSProxy.Service
{

    public class NetworkService
    {
        public NetworkService()
        {
        }

        public bool NetworkDetectionEnabled
        {
            set
            {
                if (value)
                {
                    NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
                    NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged;
                }
                else
                {
                    NetworkChange.NetworkAvailabilityChanged -= OnNetworkAvailabilityChanged;
                    NetworkChange.NetworkAddressChanged -= OnNetworkAddressChanged;
                }
            }
        }

        private void OnNetworkAddressChanged(object sender, EventArgs e)
        {
            CodeThatCanApparentlyThrow();
        }

        private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
        {
            CodeThatCanApparentlyThrow();
        }
    }
}

标签: c#exceptionevent-handlingwindows-services

解决方案


不幸的是,我只能推测为什么您的代码没有捕获到异常(并且我将这种推测保留在评论中)

但是有两个可能对您有帮助的事件,

AppDomain.UnhandledException - 这允许您为应用程序中的任何未处理异常注册一个全局处理程序。这是文档https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.unhandledexception?view=netframework-4.8

TaskScheduler.UnobservedTaskException - 因为我不熟悉您正在使用的框架库的内部结构,所以我将其包括在内,但可能在某处发生了一些异步代码,这可能不会观察任务的结果。如果错误的任务(即抛出异常)从未等待或从未访问过 Result 属性,然后超出范围,因此它可以被垃圾收集;在未来某个不确定的时间点,它将被收集并抛出 UnobservedTaskException。订阅此事件,将让您处理这种情况。文档在这里

https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler.unobservedtaskexception?view=netframework-4.8


推荐阅读