【问题标题】:Global Exception Handling for Background tasks后台任务的全局异常处理
【发布时间】:2019-10-26 12:44:12
【问题描述】:

我一直在做一个 .net Core api 项目,我根据这个例子(在解决方案中)here 实现了一个后台任务。 我已经为我的 api 控制器使用了一些全局异常处理,并且根据要求,我必须删除所有 try catch 语句并改为提供简单的 HttpStatusCodes。

我需要为我的后台任务/任务执行相同的操作,方法是创建一个全局异常处理类以从任何其他类继承,并通过记录异常而不使系统崩溃来发挥其“魔力”。我还必须避免每个请求都使用 try/catch 语句。

到目前为止我的代码 托管服务

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();
        }
    }

AsyncTask 实现

 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");


        }

我的过滤器

public class CustomExceptionFilter : IExceptionFilter
{

    public void OnException(ExceptionContext context)
     {
        //Some logic for handling exceptions.
     }
}

在我的 Startup.cs 中的服务

services.AddHostedService<MyHostedService>();
services.AddScoped<IAsyncTask, DbInternalOperation >();
services.AddMvc(options=>options.Filters.Add(new CustomExceptionFilter()));

我期待通过抛出一个异常让系统进入“OnException”方法并完成它的工作,但它没有。

我的结构有什么问题? 是否不可能从继承自 IExceptionFilter 的任何服务中捕获任何异常? 如果有人可以提供异常过滤器的基本实现以用于我的后台任务而无需 try/catch,我将不胜感激。

【问题讨论】:

    标签: c# asp.net-core scheduled-tasks


    【解决方案1】:

    过滤器和中间件仅适用于 MVC 管道,需要请求,否则管道不会启动。 IHostedService 的实现由 Host (ASP.NET Core >= 3.0) 或 WebHost (ASP.NET Core

    经典的try{}catch(Exception e) 是你需要的。

    一些来源: 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

    【讨论】:

    • 感谢您的直截了当的回答和解释。这是否意味着不在 MVC 管道下运行的任何其他服务(IHostedService 的实现除外)都不会触发过滤器/中间件?是否可以使用将另一种方法作为参数(使用委托)的方法实现某种基本服务,并在那里使用 try catch?类似public void TryMethod(Func&lt;T, T&gt; MyMethod) { try{MyMethod} catch (Exception e) { _logger.Info(e.Message);}}
    • 是的,完全正确。 Hosted-Service 与 MVC 管道无关,也可以在控制台应用程序中使用。是的,这是可能的。不过,在这种情况下,您应该使用异步方法。
    猜你喜欢
    • 2016-11-03
    • 1970-01-01
    • 2017-01-23
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 2015-12-21
    • 2011-09-29
    • 2011-06-17
    相关资源
    最近更新 更多