在类库级别捕获 C# 错误
我正在尝试为企业级类库制定错误日志记录解决方案。一些要求:
- 它将被多个端点应用程序使用(因此应该在类库中处理它)
- 它应该将其数据放入 SQL Server 数据库中以便于存储。这也涉及第三个:
- 它应该能够支持自定义 Web 应用程序读取其数据。
还有一个要求,那就是“非常高兴拥有”。也就是说,这并不重要,但如果这不可能,我最好有一个充分的理由。
- 它不应在其端点应用程序中需要专门的 Logger 对象。他们应该能够简单地抛出异常,并且日志记录软件应该从那里处理事情。不过,拥有特定的 USING 命令是正确的。
综合考虑,前三点并不困难。一个快速日志记录类和一些存储过程,中午就到此为止了,对吧?不过,最后一点我不知道如何处理。我以前在朋友的代码中看到过它,所以我知道这是可能的,但不幸的是,他的朋友已经去世了,他的代码已经丢失到了以太中。有没有人可以指出我正确的方向,让类库对象以某种方式捕获端点应用程序出现的所有错误来处理它们?
I am trying to work out an error logging solution for an enterprise-level class library. Some of the requirements:
- It will be used by multiple end-point applications (hence why it should be handled in the classlibs)
- It should sink its data into a SQL Server database for easy storage. This also goes into the third one:
- It should be able to support a custom web application reading its data.
There's one more requirement, which is a 'very nice to have'. That is, it's not critical, but if it's not feasibly possible I'd better have a darned good reason for it.
- It should not require specialized Logger objects in its end-point applications. They should be able to simply throw exceptions and the logging software should handle things from there. Having a specific USING command is kosher, though.
The first three points are not that difficult, all things considered. A quick logging class and some stored procedures, call it a day at noon, right? The last point is something I don't know how to approach, though. I've seen it done before in a friend's code, so I know it is possible, but said friend has unfortunately passed on and his code is lost to the ether. Is there anyone out there who could point me in the correct direction of having a class library object somehow catch all errors coming up from an end-point application to process them?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您想捕获并非源自您自己的调用堆栈的所有未处理的异常,您可以考虑利用 AppDomain 对象:
If you're wanting to catch all unhandled exceptions not originating within your own call stack, you could look into utilizing the AppDomain object:
听起来 Microsoft Enterprise Library 可以在这里使用...
http://msdn .microsoft.com/en-us/library/ff649552.aspx
Sounds like the Microsoft Enterprise Library could be of use here...
http://msdn.microsoft.com/en-us/library/ff649552.aspx
当我阅读企业级类库时,我脑海中浮现出这些要求:
对于作为开发人员的您来说,在睡觉前,这些要求是一本很好的读物。所有的错误场景,甚至是你最疯狂的梦想中的错误场景,迟早都会成为现实,你会在半夜凌晨 3 点尖叫着醒来。
这些要求听起来不错,但其影响是深远的。如果您尝试捕获组件中的所有错误,那么您除了隐藏错误之外什么也不做。这样的系统往往很慢,有时它们只是停止工作,没有人知道为什么,因为一些后续错误确实使系统进入了一种实际上什么都不起作用的状态。可悲的是,如果您将调试器附加到那台陈旧的机器上,您将看不到导致问题的原始错误,而是看到后续问题,您必须向后工作到原始问题。如果您想登录到 SQL Server,我可以向您保证,您最终会经常遇到没有日志或丢失日志的情况。
您应该考虑更可靠的日志目的地(自定义事件日志、日志文件……或两者)。并且不惜一切代价避免异步日志记录,因为未处理的异常会比您在日志记录线程中记录它的速度更快地导致进程崩溃。
实际上,当发生致命错误时,您需要尽早停止系统。可以在不破坏状态的情况下安全恢复的错误通常很少,但它们是值得付出努力的,因为您需要将类库设计为健壮的(处理预期错误)和安全的(抛出异常,记录它们,... )。
在设计阶段,更容易想到一个可以应对所有错误的完美系统。软件架构师喜欢这样的系统。他们可以侥幸逃脱,因为从纸面上看,它看起来不错。或者换句话说:泡沫不会破裂。
但是在执行时,您的类库正在使用
如果您尝试隐藏致命错误错误,系统只会变得更难调试,但它仍然会失败,因为您的库将消耗不完全属于您的组件的共享资源。在这种情况下,最好立即停止工作,而不是继续工作而让其他人也失败。
隐藏组件内部所有错误的想法是有缺陷的,因为您无法防止组件内部的致命错误影响系统中的其他组件。
那只蜜蜂说,我希望您不要问如何捕获类库级别的所有错误,而是在您的端点应用程序中向用户显示错误并记录它们(希望只在每一层一次而不是再次出现,因为您不信任其他层)。正如其他人指出的那样,您可以获取未处理的异常,这些异常确实终止了一个线程,当您的错误处理程序离开时,该线程又会终止您的进程。除此之外,最好在 Main 方法周围放置一个 try/catch 块以捕获主线程中的错误。如果您的应用程序有 UI(Windows 窗体),您还应该注册 Application.ThreadException 事件,当异常从 Window 消息处理程序传播出去时,该事件将被调用。
你的,
阿洛伊斯·克劳斯
When I read enterprise level class library I have these requirement in my head:
Such requirements are a good read for you as a developer before you go to bed. All error scenarios even the ones in your wildest dreams will become reality sooner or later and you wake up at 3 am in the night screaming.
The requirements sound good but its implications are far reaching. If you try to catch all errors in your component you do nothing else than error hiding. Such systems tend to be slow and sometimes they do simply stop working and nobody knows why because some follow up error did bring the system into a state where really nothing does work. The sad thing is that if you attach a debugger to that stale machine you will not see the original error that caused the problem but a follow up problem from where you have to work backwards to the original problem. If you want to log to SQL server I can assure you that you will end up with no or missing logs quite frequently.
You should consider more reliable log destinations (custom event log, log file, ... or both). And avoid async logging at all costs since an unhandled exception will bring down the process much faster than you are able to log it away in your logging thread.
In reality you need to bring the system to a halt as early as possible when a fatal error has occured. The errors from which you can safely recover without corrupting state are usually very few but they are worth the effort since you need to design your class library to be robust (deal with expected errors) and safe (throw exceptions, log them, ...).
During the design phase it is easier to think of a perfect system that can cope with all errors. Software architects like such systems. And they can get away with it because on paper it looks good. Or to put it in other words: Bubbles don´t crash.
But at execution time your class library is using
If you try to hide fatal errors the system has only become harder to debug but it will still fail since your library will is consuming shared resources which do not exclusively belong to your component. It is better to stop working immediately in such situations than to continue and let others fail as well.
The idea to hide all errors inside a component is flawed since you cannot prevent fatal errors inside your component to influence other components in the system.
That beeing said I hope you did not ask how to catch all errors at class library level but at your end-point applications where you display errors to the user and log them (hopefully only once and not again in every layer because you do not trust the other layers). As others have pointed out you can get your hands on unhandled exceptions which did terminate a thread which will in turn terminate your process when your error handler is left. Besides this it is a good idea to put a try/catch block around your Main method to catch errors in the main thread. If you application has an UI (Windows Forms) you should also register to the Application.ThreadException event which will be called when an exception propagates out of a Window message handler.
Yours,
Alois Kraus