I have a .NET Generic Host with an IHostedService
that receives events from an OPC-UA interface and that process them.
The problem is that if an unhandled exception occurs during the processing of an event, the whole application crashes
I read the documentation but I didn't find anything about a global exception handler or a similar mechanism that allows to catch unhandled exception and prevent an application crash.
Is there a solution to protect the Generic Host, as well as the IHostedService
against unhandled exceptions ?
EDIT
I know, here the simplest thing is to try/catch the exception and not let it bubble up. But I'd like to know if there is a similar mechanism like in WinForms / WPF, where you can catch such exceptions more globally and prevent a crash.
EDIT
This is a simplified version of the code:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
return new HostBuilder()
.UseEnvironment(environmentName)
.ConfigureLogging((hostContext, logging) =>
{
...
})
.ConfigureAppConfiguration((hostContext, builder) =>
{
builder
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", true, true)
.AddEnvironmentVariables();
})
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<IHostedService, OpcClientHostedService>();
...
});
}
}
public class OpcClientHostedService : IHostedService
{
private readonly OpcConfiguration _opcConfiguration;
private readonly ILogger _logger;
private readonly OpcClient _opcClient;
public OpcClientHostedService(OpcConfiguration opcConfiguration, ILogger<OpcClientHostedService> logger)
{
_opcConfiguration = opcConfiguration;
_logger = logger;
_opcClient = new OpcClient(opcConfiguration.ServerUri);
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Connecting to OPC server with URI '{0}'", _opcConfiguration.ServerUri);
try
{
_opcClient.Connect();
}
catch (Exception ex)
{
_logger.LogCritical(ex, "Cannot connect to OPC server");
throw;
}
_logger.LogInformation("Connection to OPC server is successful");
CreateOpcObservable().Subscribe(async args => await ProcessOpcEvent(args));
return Task.CompletedTask;
}
private async Task ProcessOpcEvent(OpcValueChangedEventArgs args)
{
await MethodThatCanThrowAnException(args); // If the exception is not handled, the whole application crashes!
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Disconnecting to OPC server");
_opcClient.Disconnect();
_logger.LogInformation("Disconnection to OPC server is successful");
return Task.CompletedTask;
}
...
}
In this example, it is easy to add a try/catch block in the ProcessOpcEvent
method, but it would be great to have a mechanism to avoid complete application crash in this kind of situation.