How to handle exceptions in wcf service call back - c#

I am trying to log my exceptions with AppDomain.CurrentDomain.UnhandledException.
AppDomain.CurrentDomain.UnhandledException += AppDomainUnhandledException;
public static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
HandleException(e.ExceptionObject as Exception);
}
When I get an exception in the server I will get the fault in the client at debug time but the event hooked to AppDomain.CurrentDomain.UnhandledException will never be fired.
Server:
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class Service : IService
{
public string GetError()
{
throw new ApplicationException();
}
}
Client:
public void GetError()
{
this.service.BeginGetError(OnGetErrorCompleted, null);
}
public void OnGetErrorCompleted(IAsyncResult result)
{
var value = this.service.EndGetError(result);
}
This doesn't work UNLESS I use Distpacher.BeginInvoke..
public void OnGetErrorCompleted(IAsyncResult result)
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
var value = this.service.EndGetError(result);
}));
}
Somebody knows why??
I thought AppDomain.CurrentDomain.UnhandledException would be fired in case of an exception in ANY thread! :S

A better solution is to use something like IErrorHandler and throw FaultExceptions. Decorate your operations to throw FaultExceptions using the FaultContract attribute. Now you can catch specific FaultExceptions at the client. You should not expose exceptions on the server to the client.

Related

Backup catching for exception thrown in EventHandler

I have a C# Program running as a Windows service doing some Network shenanigans
I thought I had last-ditch "Log Fatal Errors" handling set up. But I've come across an edge case where the Service ends up dead but dodges those catches. :(
I believe this is caused by code throwing an Exception in the EventHandler registered to a .NET library's event.
Obviously I can (andshould!) catch the Exception in my handler, but I'd like to understand how this is avoiding my fall-back error handling, and whether I can add some even more robust fall back logging, to ensure that I have some log records to analyse similar silent bugs in future.
The punchline of relevant code isn't terribly complex:
ServiceBase.Run(container.Resolve<MyProjectWindowsService>()); in a try ...catch in Program.Main()
MyProjectWindowsService : ServiceBase is the service object with an OnStop() implmentation.
NetworkChange.NetworkAvailabilityChanged += CodeThatThrows;
But when that Exception is thrown, neither OnStop() nor the try...catch trigger.
I can get it in a debugger, and it doesn't seem to go anywhere .. it just ... stops.
Fuller program details below, if you want them.
How can I catch and log unhandled exceptions in Event Handlers registered to external library events?
(Also ... Is the behaviour I've described above the expected behaviour, or is there something slightly weird happening?)
Program EXE entry point:
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("==========================");
}
}
}
}
Service Object
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 Registered to and ultimately invoked:
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();
}
}
}
I unfortunately can only speculate why the exception isn't being caught by your code (and I've kept that speculation to the comments)
However 2 events that might help you are,
AppDomain.UnhandledException - this allows you to register a global handler for any unhandled exceptions in your application. Here is the documentation https://learn.microsoft.com/en-us/dotnet/api/system.appdomain.unhandledexception?view=netframework-4.8
TaskScheduler.UnobservedTaskException - I've included this as I'm not familiar with the internals of the framework libraries you are using, but there maybe some asynchronous code happening somewhere, that is potentially not observing the result of a task. If a faulted task (ie an exception was thrown) is never awaited or never has the Result property accessed and then goes out of scope so it can be garbage collected; at some indeterminate point in the future, it will get collected and an UnobservedTaskException will get thrown. Subscribing to this event, will let you handle that scenario. Documentation here
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.taskscheduler.unobservedtaskexception?view=netframework-4.8
A little bit dig out what catches what on a WPF application :
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);
}
});
The output will be :
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 ...
So FirstChanceException will be catching everything (even the handled ones) and the rest won't be catching anything. My suggestion is modifying your example like this:
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
}
}
}

Should Dispose be called when rethrowing an unhandled exception?

Supposed I have a class like the below:
public class DisposableClass : IDisposable()
{
private readonly Timer timer;
DisposableClass()
{
this.timer = new Timer(s => cb(s), s, 1000, 1000);
}
Init()
{
try
{
// Do some initialization here that is not done in ctor.
}
catch (Exception)
{
// Log error.
throw;
}
finally
{
// Is this correct?
this.Dispose();
}
}
public void Dispose()
{
this.timer?.Dispose();
}
}
My question is whether the finally clause necessary (or should not have at all) in the above case, of for any non-constructor method when throwing an unhandled exception. Thanks.
EDIT:
In the answer, please address the issues depending on Init() being public,protected, private visibility levels.

How do I get Prism to report the exceptions it traps?

I have a Prism WPF application which failed to load one of its modules when I deployed it (due to a database problem). On my development machine, I can see the relevant exceptions being thrown (and apparently caught and handled by Prism) in the Output window of Visual Studio.
I was able to solve the immediate problem by doing this:
public MyModuleViewConstructor()
{
try
{
// some startup work here
// ...
InitializeComponent();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "A System Error Occurred.");
}
}
Which surfaces the error in production so that I can take action on it. But I would still like to obtain the messages from any exceptions that are thrown during normal operations, So, in the spirit of Prism's way of doing things, I did this:
public class Logger : ILoggerFacade
{
public void Log(string message, Category category, Priority priority)
{
using (StreamWriter s = File.AppendText("Log.txt"))
{
s.WriteLine(string.Format("{0}-{1}: {2}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss.ffff"), priority.ToString(), message));
s.Close();
}
}
}
And registered it in the Bootstrapper:
class Bootstrapper : DryIocBootstrapper
{
private readonly Logger _logger = new Logger();
protected override ILoggerFacade CreateLogger()
{
return _logger;
}
}
This works splendidly for normal log entries such as debug logging. But it still does not log any exceptions thrown within my application.
How do I get Prism to log thrown exceptions in my application?
When navigating, all exceptions that occur during view and/or view model creation are caught by the region manager. Those are not logged by default (although this would be a cool feature).
You can, however, be notified about the exception and log it yourself or react otherwise.
To do that, navigate through one of the IRegionManager.RequestNavigate( ..., Action<NavigationResult> navigationCallback ) overloads. The navigationCallback will be passed a result object that contains any exception in the NavigationResult.Error property.
The Prism logging mechanism is used mostly to log messages related to Prism events.
To use it for your events you could create and extension method like this
public static class LoggerExtensions
{
public static void Warn(this ILoggerFacade loger, string message)
{
using (StreamWriter s = File.AppendText("Log.txt"))
{
s.WriteLine(string.Format(" {0}-{1}: {2}", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss.ffff"), Category.Warn, message));
s.Close();
}
}
}
And to use it inside your code, you could do the following
var logger = _container.Resolve<ILoggerFacade>(); //If you use IoC
LoggerExtensions.Warn(logger, "Some exception...");
But it still does not log any exceptions thrown within my application
I would suggest to add Dispatcher.UnhandledException inside App.xaml.cs, so where ever there is any exception who is not handled, it will finish there.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
}
void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
//Your code
}
}
Update #2
I have created a small example, where to button click will throw DivideByZeroException. The Prism logging mechanism isn't aware of this exception at all. The only solution would be to use extension method, extend Exception class or other libraries.
I just don't see any other solution.
public partial class ViewA : UserControl
{
ILoggerFacade logger;
public ViewA(ILoggerFacade _logger)
{
InitializeComponent();
logger = _logger;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
var val = 0;
var result = 1500 / val;
}
catch (Exception ex)
{
LoggerExtensions.Warn(logger, ex.Message);
}
}
}

Exception handling for Singleton Events

I am using a singleton pattern for a global event manager class that is not handling exceptions in an acceptable manner.
If an exception is thrown in the code called by one of the events being executed, I always get a Exception has been thrown by the target of an invocation. error. This error contains no information related to the original exception, making it extremely difficult to debug any errors.
Is there some way to pass the original exception information back to the event manager?
public class ApplicationSettings
{
private static EventManager _manager = new EventManager();
public static EventManager EventManager
{
get { return _manager; }
}
}
The event manager class:
public class EventManager
{
public event EventHandler<ReportExecutionArgs> ExecuteReportCurrentPage;
public event EventHandler<ReportExecutionArgs> ExecuteReportNewPage;
public virtual void OnExecuteReportCurrentPage(object sender, ReportExecutionArgs e)
{
try
{
if (this.ExecuteReportCurrentPage != null)
this.ExecuteReportCurrentPage(sender, e);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public virtual void OnExecuteReportNewPage(object sender, ReportExecutionArgs e)
{
try
{
if (this.ExecuteReportNewPage != null)
this.ExecuteReportNewPage(sender, e);
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
Some other class will handle these events
ApplicationSettings.EventManager.ExecuteReportNewPage += new EventHandler<ReportExecutionArgs>(reportOpenedNewPage);
private void reportOpenedNewPage(object sender, ReportExecutionArgs e)
{
//something in this code throws an error
LitePage page = new LitePage();
_tabs.AddPage(page);
Report report = setReport(page, e);
}
EDIT
Just to clarify, the try/catch blocks in the OnExecuteReport methods are not catching the exception.
A TargetInvocationException such as the one you describe will almost always have the originating exception in it's InnerException.

How to access initial parameters in the callback of an asynchronous WCF request?

I'm currently updating a client application that makes use of a WCF web service from synchronous to asynchronous calls. The main server and the client are on the same local network, but it is too unreliable for the application to hang while it waits for a response.
The application makes use of 4 identical endpoints across 2 servers (so if an instance has crashed or a server is offline, there should still be something to call).
The client has a layer responsible for making calls to the web service. My initial synchronous design was for the the active endpoint to be called and if an exception was thrown we would then move to the next endpoint and recursively call the same method. This would be done until all endpoints are exhausted.
I've now made the modifications to make this async but there is one issue. The parameters are lost once we are in the callback. So when it it time to call the Begin method again recursively, the parameters are not accessible to be passed in again.
What would be the best way to pass parameters from the Begin method to the callback method? Are they stored anywhere in the client object? Can it be done through the event or should I store them at the class level?
public delegate void GetUserInfoCompletedEventHandler(UserInfo e);
public static event GetUserInfoCompletedEventHandler GetUserInfoCompleted;
public delegate void GetUserInfoFaultedEventHandler(string errorMessage);
public static event GetUserInfoFaultedEventHandler GetUserInfoFaulted;
public static void BeginGetUserInfo(string fobID)
{
MyClient client = new MyClient(availableEndpoints[activeEndpointIndex].Name);
client.GetUserInfoCompleted += new EventHandler<GetUserInfoCompletedEventArgs>(client_GetUserInfoCompleted);
client.GetUserInfoAsync(fobID);
}
static void client_GetUserInfoCompleted(object sender, GetUserInfoCompletedEventArgs e)
{
// Get the instance of the client
MyClient client = (MyClient)sender;
if (null == e.Error)
{
// Close the client instance if there was no error
try { client.Close(); }
catch { }
if ((null != GetUserInfoCompleted) && (null != e.Result))
{
// Report as successful and raise the event
ServiceActionSuccessful();
GetUserInfoCompleted(e.Result);
}
}
else
{
// Abort the client as there was an error
try { client.Abort(); }
catch { }
if (e.Error is FaultException<WebServiceError>)
{
FaultException<WebServiceError> fault = (FaultException<WebServiceError>)e.Error;
if (null != GetUserInfoFaulted)
{
// A fault occurred in the web service
GetUserInfoFaulted(fault.Detail.ErrorMessage);
}
}
else
{
// Assume this was problem in connection so test if there any more endpoints to attempt
bool isNextEndpointAvaialble = ServiceActionFailure();
if (isNextEndpointAvaialble)
{
// If there are more endpoints to try, call the method to run again
BeginGetUserInfo(); // Need parameters here
}
else
{
if (null != GetUserInfoFaulted)
{
// No more endpoints to try
GetUserInfoFaulted(Errors.GetUserFriendlyMessage(e.Error));
}
}
}
}
}
If MyClient is a generated class, there should be a second function called
MyClient.GetUserInfoAsync(string fobID, object userState);
The content of the userState argument is passed dirctly to the GetUserInfoCompletedEventArgs.UserState property in the eventargs received by client_GetUserInfoCompleted.
So you could do something like this:
public static void BeginGetUserInfo(string fobID)
{
MyClient client = new MyClient(availableEndpoints[activeEndpointIndex].Name);
client.GetUserInfoCompleted += new EventHandler<GetUserInfoCompletedEventArgs>(client_GetUserInfoCompleted);
client.GetUserInfoAsync(fobID, fobID);
}
static void client_GetUserInfoCompleted(object sender, GetUserInfoCompletedEventArgs e)
{
string fobID = e.UserState as string;
// handle the event here...
}
Another alternative is to use a lambda for handling the event:
public static void BeginGetUserInfo(string fobID)
{
MyClient client = new MyClient(availableEndpoints[activeEndpointIndex].Name);
client.GetUserInfoCompleted += (sender, args) => client_GetUserInfoCompleted(sender, args, fobID);
client.GetUserInfoAsync(fobID);
}
static void client_GetUserInfoCompleted(object sender, GetUserInfoCompletedEventArgs e, string fobID)
{
// access the additional parameter fobID here
}

Categories