问题
I have been working on a .net Core api project and I implemented a background task based on this example (in solution) here . I am already using some Global Exception handling for my api controllers, and by requirement I had to remove all the try catch statements and give simple HttpStatusCodes instead.
I am required to do the same for my background task/tasks by creating a global Exception handling class to be inherited from any other class and work its "magic" by logging the exception without crashing the system. I also have to avoid try/catch statements per request.
My code so far The HostedService
public class MyHostedService : CustomExceptionFilter, IHostedService
{
private Timer _timer;
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger _logger;
public SchedulerHostedService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
_logger = new LoggerManager();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.Info("Background Service is starting");
_timer = new Timer(ExecuteTask, null, TimeSpan.Zero, TimeSpan.FromMinutes(30));
return Task.CompletedTask;
}
private void ExecuteTask(object state)
{
_ = ExecuteTaskOperationAsync();
}
private async Task ExecuteTaskOperationAsync()
{
using (IServiceScope scope = _scopeFactory.CreateScope())
{
IAsyncTask service = scope.ServiceProvider
.GetRequiredService<IAsyncTask>();
await service.CustomTaskAsync();
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.Info("Background Service is stopping");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
The AsyncTask implementation
internal interface IAsyncTask
{
Task CustomTaskAsync();
}
public class DbInternalOperation : CustomExceptionFilter, IAsyncTask
{
private readonly MyDbContext _context;
private readonly ILogger _logger;
public DbInternalOperation(MyDbContext context)
{
_context = context;
_logger = new Logger();
}
public async Task CustomTaskAsync()
{
//All db logic to update some records based on date.
throw new Exception("Test");
_logger.Info($"Scheduled operation started");
//Some code for dbcontext
await _context.SaveChangesAsync();
_logger.Info($"Scheduled operation finished");
}
My Filter
public class CustomExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
//Some logic for handling exceptions.
}
}
and in my Startup.cs in services
services.AddHostedService<MyHostedService>();
services.AddScoped<IAsyncTask, DbInternalOperation >();
services.AddMvc(options=>options.Filters.Add(new CustomExceptionFilter()));
I was expecting by throwing an exception for the system to go in the 'OnException' method and do its work, but it didn't.
What is wrong in my structure here? Is it not possible to catch any exception from any services that inherit from IExceptionFilter? I would appreciate it if anyone could provide a basic implementation of an exception filter to be used for my background tasks without try/catch.
回答1:
Filters and Middleware are only available for the MVC-pipeline, a request is required otherwise the pipeline doesn't start. Implementations of IHostedService
are triggered by the Host
(ASP.NET Core >= 3.0) or WebHost
(ASP.NET Core < 3.0) and do not run within the MVC-pipeline.
Classical try{}catch(Exception e)
is what you need here.
Some sources: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.2 https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2
来源:https://stackoverflow.com/questions/56554793/global-exception-handling-for-background-tasks