C# 在EventHandler中引发异常的备份捕获
我有一个C#程序作为Windows服务运行,执行一些网络恶作剧 我以为我已经设置了“记录致命错误”的最后一搏。但我遇到了一个边缘案例,该服务最终死亡,但却躲开了那些陷阱( 我认为这是由于代码在注册到.NET库的事件的EventHandler中引发异常所致 显然,我可以(而且应该!)在我的处理程序中捕获异常,但我想了解这是如何避免我的回退错误处理的,以及我是否可以添加一些更健壮的回退日志记录,以确保我有一些日志记录,以便将来分析类似的静默错误C# 在EventHandler中引发异常的备份捕获,c#,exception,event-handling,windows-services,C#,Exception,Event Handling,Windows Services,我有一个C#程序作为Windows服务运行,执行一些网络恶作剧 我以为我已经设置了“记录致命错误”的最后一搏。但我遇到了一个边缘案例,该服务最终死亡,但却躲开了那些陷阱( 我认为这是由于代码在注册到.NET库的事件的EventHandler中引发异常所致 显然,我可以(而且应该!)在我的处理程序中捕获异常,但我想了解这是如何避免我的回退错误处理的,以及我是否可以添加一些更健壮的回退日志记录,以确保我有一些日志记录,以便将来分析类似的静默错误 相关代码的要点并不十分复杂: ServiceBase
相关代码的要点并不十分复杂:
ServiceBase.Run(container.Resolve());
在try…catch中运行Program.Main()
MyProjectWindowsService:ServiceBase
是带有OnStop()实现的服务对象。
NetworkChange.NetworkAvailabilityChanged+=CodeThatThrows;
但是当抛出该异常时,无论是OnStop()
还是try…catch
触发器。
我可以在调试器中获取它,它似乎不会去任何地方。它只是…停止
如果您需要,请在下面提供更全面的计划详细信息
如何在注册到外部库事件的事件处理程序中捕获并记录未处理的异常?
(还有……我上面描述的行为是预期的行为,还是发生了一些稍微奇怪的事情?)
程序EXE入口点:
使用系统;
使用System.ServiceProcess;
使用Autofac;
使用Autofac.Extras.NLog;
使用NLog;
名称空间MyProject.Service
{
内部静态类程序
{
私有静态只读ILogger Logger=LogManager.GetCurrentClassLogger();
///
///应用程序的主要入口点。
///
私有静态void Main()
{
尝试
{
//var容器=…DI安装程序。。。
Run(container.Resolve());
}
捕获(例外情况除外)
{
记录器错误(例如,“意外错误”);
}
最后
{
Logger.Info(“====================================================”);
Logger.Info(“Windows服务已停止(2)”;
Logger.Info(“====================================================”);
}
}
}
}
服务对象
使用系统;
使用System.ServiceModel;
使用System.ServiceProcess;
使用Autofac;
使用Autofac.Integration.Wcf;
使用NLog;
名称空间MyProject.Service
{
公共类MyProjectWindowsService:ServiceBase
{
专用只读ILogger\u记录器;
公共DNSProxyWindowsService(ILogger记录器)
{
ServiceName=Constants.SERVICE\u NAME;
_记录器=记录器;
}
启动时受保护的覆盖无效(字符串[]args)
{
_logger.Info(“=======================================================”);
_logger.Info(“DNProxy Windows服务已启动”);
_logger.Info(“=======================================================”);
//其他活动设置步骤
}
受保护的覆盖void OnStop()
{
尝试
{
//其他主动关闭步骤。
}
捕获(例外情况除外)
{
_logger.Error(例如,“无法整齐地关闭服务”);
}
最后
{
_logger.Info(“====================================================”);
_logger.Info(“Windows服务已停止(1)”;
_logger.Info(“====================================================”);
}
}
}
}
EventListener已注册并最终被调用:
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
Net系统;
使用System.Net.NetworkInformation;
使用System.Net.Sockets;
使用NLog;
使用Exception=System.Exception;
命名空间DNSProxy.Service
{
公共类网络服务
{
公共网络服务()
{
}
公共布尔网络检测已启用
{
设置
{
如果(值)
{
NetworkChange.NetworkAvailabilityChanged+=OnNetworkAvailabilityChanged;
NetworkChange.NetworkAddressChanged+=OnNetworkAddressChanged;
}
其他的
{
NetworkChange.NetworkAvailabilityChanged-=OnNetworkAvailabilityChanged;
NetworkChange.NetworkAddressChanged-=OnNetworkAddressChanged;
}
}
}
私有无效OnNetworkAddressChanged(对象发送方,事件参数e)
{
可以明显抛出()的代码;
}
私有无效OnNetworkAvailabilityChanged(对象发送方,NetworkAvailabilityEventArgs e)
{
可以明显抛出()的代码;
}
}
}
不幸的是,我只能推测为什么您的代码没有捕捉到异常(我一直将这种推测保留在注释中)
然而,可能对您有所帮助的两个事件是
AppDomain.UnhandledException-这允许您为应用程序中任何未处理的异常注册全局处理程序。以下是文档
TaskScheduler.UnobservedTaskeException-我之所以包含这一点,是因为我不熟悉您正在使用的框架库的内部结构,但可能在某个地方发生了一些异步代码,可能没有观察到任务的结果。如果出现错误的任务(即引发异常)从未等待或从未访问过结果属性,然后超出范围,因此可以对其进行垃圾收集;在将来的某个不确定点,
var domain = AppDomain.CurrentDomain;
domain.UnhandledException += (o, args) =>
{
Debug.WriteLine("Catched in UnhandledException");
Debug.WriteLine(args.ExceptionObject);
};
domain.FirstChanceException += (o, args) =>
{
Debug.WriteLine("Catched in FirstChanceException");
Debug.WriteLine(args.Exception);
};
TaskScheduler.UnobservedTaskException += (o, args) =>
{
Debug.WriteLine("Catched in UnobservedTaskException");
Debug.WriteLine(args.Exception);
};
Task.Factory.StartNew(async () =>
{
Debug.WriteLine("Workinf");
await Task.Delay(1000);
try
{
throw new Exception("oops");
}
catch (Exception exception)
{
throw new Exception("oopps catched", exception);
}
});
Exception thrown: 'System.Exception' in WpfApp1.exe
Catched in FirstChanceException
System.Exception: oops
at ....
Exception thrown: 'System.Exception' in WpfApp1.exe
Catched in FirstChanceException
System.Exception: oopps catched ---> System.Exception: oops
at ...
--- End of inner exception stack trace ---
at ...
public class NetworkService
{
private readonly SynchronizationContext currContext;
public NetworkService()
{
this.currContext = SynchronizationContext.Current;
}
private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
try
{
CodeThatCanApparentlyThrow();
}
catch (Exception exception)
{
this.currContext.Post(s => throw exception, null); // this will propagate your exception into main thread
}
}
}