A global error handler for a class library in C# - c#

Is there a way to catch and handle an exception for all exceptions thrown within any of the methods of a class library?
I can use a try catch construct within each method as in sample code below, but I was looking for a global error handler for a class library. The library could be used by ASP.Net or Winforms apps or another class library.
The benefit would be easier development, and no need to repeatedly do the same thing within each method.
public void RegisterEmployee(int employeeId)
{
try
{
....
}
catch(Exception ex)
{
ABC.Logger.Log(ex);
throw;
}
}

You can subscribe to global event handler like AppDomain.UnhandledException and check the method that throws exception:
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
var exceptionObject = unhandledExceptionEventArgs.ExceptionObject as Exception;
if (exceptionObject == null) return;
var assembly = exceptionObject.TargetSite.DeclaringType.Assembly;
if (assembly == //your code)
{
//Do something
}
}

Related

How to make exception handler using events

I have dll Scripting. In that dll I have class named Scripter. In Scripter class i call some methods which loads data from MySQL database (LoadTables()). In that functions which loads data from MySQL database exception could happen. I want to be able, later in my app where I use Scripting.dll, to do something like this:
Scrpter sc = new Scripter();
sc.OnError += ErrorOccured;
And want to have function ErrorOcured in my app which will be like:
private void ErrorOccured(Exception exception)
{...}
What I need to have in Scripter class, and how should I pass exception in catch block in LoadTables so I could later use ErrorOcured() to see what happend wrong?
As Picoh and Zoltan commented on your question, you can easily wrap method calls to Scripter methods in try/catch block. But, if you want to use event (with custom args), you can do something like this:
//your class
public class Scripter
{
public Scripter()
{
}
//public event with custom event args
public EventHandler<ScripterErrorEventArgs> OnError;
//just for test
public void RaiseError()
{
//error which is caught here
Exception ex = new Exception("something happened");
OnError?.Invoke(this, new ScripterErrorEventArgs(ex));
}
}
//class for custom event args. add your own other properties as needed
public class ScripterErrorEventArgs : EventArgs
{
public ScripterErrorEventArgs()
{
}
public ScripterErrorEventArgs(Exception ex)
{
this.Exception = ex;
}
public Exception Exception { get; set; }
}
//usage
public void someMethod()
{
Scripter s = new Scripter();
s.OnError += new EventHandler<ScripterErrorEventArgs>(LogError)
s.RaiseError();
}
private void LogError(object sender, ScripterErrorEventArgs e)
{
//your code here
}
You could try to modify your Scripter class like this
class Scripter
{
public event EventHandler<Exception> ErrorOcurred;
protected virtual void OnErrorOcurred(Exception e)=>ErrorOcurred?.Invoke(this, e);
public void ThrowsException()
{
try
{
throw new Exception("Throws exception");
}
catch (Exception ex)
{
OnErrorOcurred(ex);
}
}
}
This way you can subscribe to ErrorOcurred and receive notifications about exceptions. You must call OnErrorOcurred in every place you catch an exception
Hope this helps

Exception throw behavior

So I have this exception I want to throw if something goes wrong. But it acts strange.
public Calendar LoadCalendar(){
...
if (cal == null)
{
throw new NotImplementedException();
}
_lastPollTime = DateTime.Now;
...
}
I expect this exception to be thrown to wherever LoadCalendar was called. Instead, the program stops at DateTime.Now; because of "NotImplementedException()".
What am I doing wrong? How could I throw it to the end of the method instead?
You need to add a "catch" clause somewhere up the call stack which receives the thrown exception and deals with it somehow.
You could try this in your programs Main function:
static void Main()
{
try
{
// put existing code here
}
catch( Exception e )
{
}
}
Without a catch, the exception has no place to go to and so instead it causes your program to terminate.
These guidlines for working with exceptions might be useful to you: http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
Just subscribe DispatcherUnhandledException event in App.xaml.cs Class Constructor and you can handle any application exception in this event.
public partial class App : Application
{
public App()
{
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
}
void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
////Handle your application exception's here by e.Exception.
}
}

C# transmit exception from class to Form

How can I pass an error in the form of the class. When creating exemplar class.
Class:
class ThreadSafeLog
{
public ThreadSafeLog()
{
try
{
if (!File.Exists(Path_))
{
using (File.Create(Path_)) { }
}
}
catch(Exception e)
{
MessageBox.Show(e.Message);//error transmit exception to Form
}
}
}
Form:
ThreadSafeLog log = new ThreadSafeLog(
#"R:\project\ThreadSafeLog\ThreadSafeLogTest\ThreadSafeLogTest\bin\");
Why would ThreadSafeLog be concerned with what the form that uses it is doing? How is it even supposed to know it's being used by a form? Catch the exception in the form instead.
class ThreadSafeLog
{
public ThreadSafeLog()
{
if (!File.Exists(Path_))
{
using (File.Create(Path_)) { }
}
}
}
Form:
try
{
ThreadSafeLog log = new ThreadSafeLog(
#"R:\project\ThreadSafeLog\ThreadSafeLogTest\ThreadSafeLogTest\bin\");
}
catch (Exception ex)
{
MessageBox.Show(e.Message);
}
Though, as Adriano points out, you may also want to question why you're displaying internal error details directly to users.
I would not notify log's users about an error inside the logger itself. Log is, usually, a subsystem that it's good to consider error-safe and thread-safe or you'll make your code a messy. Imagine:
try
{
// Do something that may fail
}
catch (SomeException e)
{
try
{
logger.Log(e);
}
catch (IOException)
{
// Ooops, log doesn't work. What should I do?
// Should I display a MessageBox?
}
}
Your code will become quickly a messy (imagine to repeat the same check again and again for each trace log).
What I would do is to ignore (if possible) errors inside log function and to take another action instead. How? Just add an event to your log class (code is an example not for production!):
class Logger
{
public event EventHandler<LogErrorEventArgs> Error;
public void Log(Exception e)
{
try
{
// Try to write log somewhere...
}
catch (IOException internalException)
{
EventHandler<LogErrorEventArgs> error = Error;
if (error != null)
error(this, new LogErrorEventArgs(e, internalException);
}
}
}
In this way unhandled errors inside logger will go unnoticed (if this is applicable) or they may be handled (in the way it's appropriate, if there is a way). For example:
Logger logger = new Logger();
logger.Error += delegate(object sender, LogErrorEventArgs e)
{
if (SystemInformation.UserInteractive)
MessageBox.Show(e.ExceptionToLog.Message);
};
You may attach multiple handlers too (for example to log to Windows Log and notify user is session is interactive). When you use log you won't be aware it may fail (so you won't have to fill your code with try/catch everywhere) but if needed you may still be notified and errors inside log will be handled in a consistent manner.
Now let's rewrite the code in our first example like this:
try
{
// Do something that may fail
}
catch (SomeException e)
{
logger.Log(e);
}
Straight, right? I assumed logger will always write an exception (somehow) but it's easy to change code to handle a raw String instead. I omitted code for LogErrorEventArgs because pretty obvious anyway it may look like this:
class LogErrorEventArgs : EventArgs
{
public LogErrorEventArgs(
Exception exceptionToLog,
Exception internalLoggerException)
{
ExceptionToLog = exceptionToLog;
InternalLoggerException = internalLoggerException;
}
public Exception ExceptionToLog
{
get;
set;
}
public Exception InternalLoggerException
{
get;
set;
}
}

ServiceBase.Run, why can't I catch it's exceptions, or react to them in some other way?

I'm calling the following from my entry point static main method:
try { ServiceBase.Run(new MonitorSer()); }
catch (Exception ex) { Console.WriteLine(ex.Message + Process.GetCurrentProcess().MainModule.FileName); }
MonitorSer is an instance of:
class MonitorSer : ServiceBase {
and the entry main method is a member of my class:
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer {
I've had good results catching exceptions for debugging but sometimes they seem to find their own way around my traps, as in this case.
I get a windows box flash up telling me I need to install using installutil when what I really want is to find the name of this process and call it again with the -i switch which I have wired up to make it install intself (credit to those here who contributed/recycled that code).
What makes this more frustrating is that if I set breakpoints upto (or on) the call to ServiceBase.Run, it will fail silently and I am left with the blinking console.
UPDATE
static void Install(bool undo, string[] args)
{
try
{
Console.WriteLine(undo ? "uninstalling" : "installing");
using (AssemblyInstaller inst = new AssemblyInstaller(typeof(MonitorSer).Assembly, args))
{
IDictionary state = new Hashtable();
inst.UseNewContext = true;
try
{
if (undo) inst.Uninstall(state);
else
{
inst.Install(state);
inst.Commit(state);
}
}
catch
{
try
{
inst.Rollback(state);
}
catch { }
throw;
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
I clumped the entry point here so I could call the above function, I'll try moving that to another class and setting the entry point there, but I know I can make this entry point (that you, Dmitry, deny) work by calling itself with the appropriate argument to install- which only the BaseService class can do- correct me if I am wrong.
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
Is not your entry point. This will get called once when you install your service using InstallUtil.exe. Entry point can be specified in the project properties and it usually defaults to Program.Main. You should not be starting your service from Installer class.
CLR will let you know of unhandled exceptions if you subscribe to this event:
static void Main() {
...
AppDomain.CurrentDomain.UnhandledException
+= CurrentDomain_UnhandledException;
...
}
private static void CurrentDomain_UnhandledException(
Object sender,
UnhandledExceptionEventArgs e) {
if (e != null && e.ExceptionObject != null) {
// log exception:
}
}
This event provides notification of uncaught exceptions. It allows the
application to log information about the exception before the system
default handler reports the exception to the user and terminates the application
...
Starting with the .NET Framework version 4, this event is not raised
for exceptions that corrupt the state of the process, such as stack
overflows or access violations, unless the event handler is
security-critical and has the
HandleProcessCorruptedStateExceptionsAttribute attribute.
application.
Another place where you might want to log exceptions in windows service (because .NET/SCM will swallow startup exceptions):
protected override void OnStart(String[] args) {
try {
} catch(Exception e) {
// log exception:
throw;
}
}

calling the other functions when an exception is thrown - C# delegates

if a delegate points to 5 methods, when delegate is invoked an excpetion happens in first method. since the exception happens the rest of the 4 functions cannot be called. How to make the delegate to call other functions even when exceptions happpens
You'd need to use Delegate.GetInvocationList to basically split the delegate into the individual actions, and call each in turn with a catch clause to handle the exceptions.
For example:
Action[] individualActions = (Action[]) multicast.GetInvocationList();
foreach (Action action in individualActions)
{
try
{
action();
}
catch (Exception e)
{
// Log or whatever
}
}
You may want to only catch specific types of exception, of course.
You will have to call (Invoke) the subscribed handlers yourself, inside a try/catch block. You can get the list with GetInvocationList().
The better solution requires control over the handlers: They should not throw.
The rough code for handling the exceptions:
foreach (Delegate handler in myDelegate.GetInvocationList())
{
try
{
object params = ...;
handler.Method.Invoke(handler.Target, params);
}
catch(Exception ex)
{
// use ex
}
}
May be following code will help you understand how to do that.
public class DynamicInvocation
{
public event EventHandler SomeEvent;
public void DoWork()
{
//Do your actual code here
//...
//...
//fire event here
FireEvent();
}
private void FireEvent()
{
var cache = SomeEvent;
if(cache!=null)
{
Delegate[] invocationList = cache.GetInvocationList();
foreach (Delegate #delegate in invocationList)
{
try
{
#delegate.DynamicInvoke(null);
}
catch
{
}
}
}
}
}

Categories

Resources