在项目中经常会出现一个难以理解的错误,对于该错误,必须
将所有查询的最大日志记录到数据库中
。 本文将帮助那些在
Asp.Net Boilerplate上编写(部署在服务器上)第一个项目之一的
人 。
本文针对的是Asp.Net Boilerplate技术的新手,他们遇到了与数据库有关的任何奇怪的错误。 使用PostgreSQL时,例如,这可能是第一个项目。 撰写本文的动机是,即使在英语中,也很难在Internet上找到该问题的解决方案,更不用说找到的解决方案不能完全回答有关此问题的所有问题。
产品版本:Asp.Net Boilerplate 4.3,.NET Core 2.1
如果完成这些步骤 :在主日志文件中,您将看到登录到数据库的所有请求。
第一步
您必须创建一个记录器。 Boilerplate平台上已经有一个配置好的内部记录器。 它可以是标准的Log4Net。 无需对他进行任何操作。 相反,创建一个记录器类就足够了,您可以将其注册为数据库中所有日志消息的处理程序。
步骤1.1
项目* .EntityFrameworkCore。 在这里,我们需要创建2个类。 一方面,仅做一件事的记录器就是将所有消息从数据库输出到系统日志。 我们称之为
MyLogger。 以及将创建MyLogger的该记录器的提供者。 该提供程序称为
MyLoggerProvider。我们使用以下代码创建一个文件(为简化起见,一个文件,尽管当然每个文件都应具有一个类):
public class MyLoggerProvider : ILoggerProvider { private Castle.Core.Logging.ILogger _logger; public MyLoggerProvider(Castle.Core.Logging.ILogger logger) { _logger = logger; } public ILogger CreateLogger(string categoryName) { return new MyLogger(_logger); } public void Dispose() { } } public class MyLogger : ILogger { private Castle.Core.Logging.ILogger _logger; public MyLogger(Castle.Core.Logging.ILogger logger) { _logger = logger; } public IDisposable BeginScope<TState>(TState state) { return null; } public bool IsEnabled(LogLevel logLevel) { return true; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { if (IsEnabled(logLevel)) { var msg = formatter(state, exception); _logger.Info("DB-REQUEST: " + msg); } } }
如果仔细观察,您可以看到其他一些记录器如何转发到MyLoggerProvider,然后转发到MyLogger。 原来已经是第三个了! 最重要的是,这第三类是日志记录基础结构级别的类,必须从Boilerplate的肠子中获取这些消息,并将其保存在日志中。 见下文。
第二步
在同一个* .EntityFrameworkCore项目的框架内,转到* DbContextConfigurer.cs文件,并在两个Configure()方法中进行以下更改:
2.1)添加LoggerFactory类型的loggerfactory参数
2.2)在方法主体中添加两行:
builder.UseLoggerFactory(loggerFactory); builder.EnableSensitiveDataLogging(true);
UseLoggerFactory的含义是启用
loggerFactory的使用,它在记录数据库的参数中传递。 重要的是要记住,这里我们启用了数据库日志记录。
EnableSensitiveDataLogging的含义是不仅允许记录数据库查询,而且还记录这些查询中的所有数据。 没有此设置,您将无法在查询中看到数据-它们将被问号替换。
第三步
在同一个* .EntityFrameworkCore项目的框架内,我们转到* DbContextFactory.cs文件。
3.1)添加新方法:
private LoggerFactory GetDbLoggerFactory() { return new LoggerFactory(new[] { new MyLoggerProvider(NullLogger.Instance) }); }
3.2)在CreateDbContext()方法中:
因为 由于我们之前已向两个Configure()实现添加了新参数,因此此处应显示错误。 现在是时候指定这个新参数了-我们用逗号注册GetDbLoggerFactory()。 即 新的loggerFactory参数的值应由第3.1节中的新方法返回。
第4步
在同一个* .EntityFrameworkCore项目的框架内,我们转到* EntityFrameworkModule.cs文件。
4.1)添加新方法:
private LoggerFactory GetDbLoggerFactory() { return new LoggerFactory(new[] { new MyLoggerProvider(Logger) }); }
4.2)在PreInitialize()方法中:
因为 由于我们之前已向两个Configure()实现添加了新参数,因此此处也应显示错误。 我们类似于3.2节指定一个新参数-我们用逗号注册GetDbLoggerFactory()。 即 新的loggerFactory参数的值应由第4.1节中的新方法返回。
结果
在主日志文件(默认为Logs.txt)中,您将看到所有以DB-REQUEST字符序列开头的查询(正是从该查询中可以在日志中搜索数据)。
解决方案的一般理解
所以,现在我将解释我们所做的事情。 本文末尾给出了解释,因为 读者通常对开始做一些特定的事情感兴趣。
在类* DbContextFactory和EntityFrameworkModule中,我们创建LoggerFactory,并在其参数中指示创建的MyLoggerProvider。 但是,作为将直接登录第一种情况(* DbContextFactory)的基础结构类,我们传递了NullLogger.Instance存根,因此没有任何条目。 在第二种情况下(* EntityFrameworkModule),我们通过记录器,该记录器已经在Abp模块中。 这是“记录器”字段。 它已经被初始化并且可以与它一起记录。 因此,我们的MyLogger将能够使用此类写入Logs.txt文件。
整个逻辑是将此loggerFactory工厂安装为用于与数据库一起工作的日志工厂。 一旦需要一个记录器,它就由工厂创建。 这就是我们的MyLogger,它依次记录Logs.txt(或配置您的主日志输出的源)中的所有内容。
如您所见,并不是所有的事情都那么简单,抽象的层次有时会冻结,特别是对于初学者! 在评论中提出您的问题。
注意事项:-创建解决方案是为了打开记录器,了解错误是什么并将其关闭。 它不是为长期使用而设计的。