You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core如何为Logger添加异常处理并将日志存储至数据库

实现方案

总共分两步,先搞定全局异常自动日志记录,再实现日志落库。

一、未处理异常自动记录

你现在抛异常没日志的原因很简单:

  • Index方法里throw new Exception("testing")之后的代码不会执行,你写的访问日志逻辑根本跑不到
  • 没有全局异常拦截机制,未处理异常不会自动走到日志记录流程里

不要在每个Action里套try-catch,直接用全局异常中间件统一处理,覆盖所有接口和页面:
在Program.cs(.NET 6+)或Startup.Configure中,把异常处理中间件放到所有其他中间件的最前面:

// 开发环境保留开发者异常页,生产环境用自定义异常处理
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler(errorApp =>
    {
        errorApp.Run(async context =>
        {
            var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>();
            if (exceptionFeature?.Error != null)
            {
                var logger = context.RequestServices.GetRequiredService<ILogger<CascadingController>>();
                // 直接把异常对象传给LogError,自动记录错误消息、堆栈、请求路径
                logger.LogError(exceptionFeature.Error, "请求路径 {Path} 发生未处理异常", context.Request.Path);
                
                context.Response.StatusCode = StatusCodes.Status500InternalServerError;
                // 跳转到你项目里已经写好的Error页
                context.Response.Redirect("/Cascading/Error");
                return;
            }
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        });
    });
}
else
{
    app.UseDeveloperExceptionPage();
}
// 后面放你原来的中间件:UseHttpsRedirection、UseRouting、UseAuthorization、MapControllerRoute这些

加完之后,任何Action抛出的未处理异常都会被自动捕获并记录,不需要单独在业务代码里加异常处理逻辑。

二、日志持久化到数据库

你项目已经集成了EF Core,直接自定义日志提供程序,把所有ILogger输出的日志(包括你手动写的访问日志、全局捕获的异常日志)自动存到数据库即可,不需要引入第三方组件。

  1. 首先新增日志表实体,放到Models目录下:
    public class SystemLog
    {
        public long Id { get; set; }
        public string LogLevel { get; set; }
        public string Category { get; set; }
        public string Content { get; set; }
        public string? ExceptionStack { get; set; }
        public DateTimeOffset CreateTime { get; set; }
    }
    
  2. 在你现有的newnewContext中添加对应DbSet:
    public DbSet<SystemLog> SystemLogs { get; set; }
    
    执行EF Core迁移命令创建日志表:
    Add-Migration AddSystemLogTable
    Update-Database
    
  3. 编写自定义日志提供程序,实现日志写入数据库的逻辑:
    public class EfCoreLogger : ILogger
    {
        private readonly string _category;
        private readonly IServiceProvider _sp;
    
        public EfCoreLogger(string category, IServiceProvider sp)
        {
            _category = category;
            _sp = sp;
        }
    
        public IDisposable? BeginScope<TState>(TState state) where TState : notnull => default;
        public bool IsEnabled(LogLevel logLevel) => logLevel != LogLevel.None;
    
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
        {
            if (!IsEnabled(logLevel)) return;
            // 手动创建作用域解析DbContext,避免单例日志组件直接引用Scoped生命周期的DbContext
            using var scope = _sp.CreateScope();
            var dbContext = scope.ServiceProvider.GetRequiredService<newnewContext>();
            
            dbContext.SystemLogs.Add(new SystemLog
            {
                LogLevel = logLevel.ToString(),
                Category = _category,
                Content = formatter(state, exception),
                ExceptionStack = exception?.ToString(),
                CreateTime = DateTimeOffset.Now
            });
            dbContext.SaveChanges();
        }
    }
    
    public class EfCoreLoggerProvider : ILoggerProvider
    {
        private readonly IServiceProvider _sp;
        public EfCoreLoggerProvider(IServiceProvider sp) => _sp = sp;
        public ILogger CreateLogger(string categoryName) => new EfCoreLogger(categoryName, _sp);
        public void Dispose() { }
    }
    
  4. 在Program.cs的服务注册部分,把自定义日志提供程序注册到容器:
    var builder = WebApplication.CreateBuilder(args);
    // 这里放你原来的服务注册代码:AddControllersWithViews、AddDbContext等
    // 注册自定义日志提供程序
    builder.Services.AddSingleton<ILoggerProvider, EfCoreLoggerProvider>();
    

补充说明

  • 你现有Index方法里throw语句之后的访问日志是死代码,永远不会执行,如果需要记录访问日志,把日志代码移到throw前面即可。如果要统一记录所有请求的访问日志,直接加个请求日志中间件就行,不用每个Action单独写。
  • 小项目用上面的同步写库逻辑完全够用,如果接口访问量高,可以加个内存队列做异步批量写入,避免每次日志IO影响接口响应速度。
  • 你之前在Country、State、District方法里写的LogInformation访问日志,加完自定义日志提供程序之后会自动存到数据库,不需要修改原有代码。

内容的提问来源于stack exchange,提问作者gourav kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 03:03:22