我正在使用 EF 命令拦截器在命令执行后将一些数据保存到数据库。 (我有一些过滤器只在我想要的命令上运行它,所以它不会变成无限循环)
class EFCommandInterceptor : IDbCommandInterceptor
{
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
var log = new LogModel
{
DateTime = DateTime.Now,
Log = "Log"
};
using (var context = new ApplicationDbContext())
{
context.Logs.Add(log);
var res = context.SaveChangesAsync().Result;
}
}
}
这在大多数情况下都可以正常工作。但是如果我有任何需要记录在事务中的命令
using (TransactionScope transaction = new TransactionScope())
{
// Some commands to intercept
}
我收到一个错误
<块引用>var res = context.SaveChangesAsync().Result;
Win32Exception: The wait operation timed out
我已经尝试延长连接超时和命令超时计时器,但比抛出相同错误需要更长的时间。
我也试过在拦截器中创建一个新的 sql 连接和一个命令,但得到同样的错误。
EF Command Interceptor 拦截来自事务内部的命令时,有没有办法将数据保存到数据库中?
如果没有,拦截器有没有办法忽略事务内部的命令?
答案 0 :(得分:0)
一般来说,最好使用单独的日志记录框架进行日志记录,例如 log4net、NLog 或 Serilog,因为这些记录器会在自己的线程中进行日志记录,并且应该对环境事务不敏感。
在 .Net core 5 下使用 Serilog 进行的快速测试表明,即使在 TransactionScope
内调用时,它也会记录日志,启用异步流,即回滚:
using Serilog;
using Serilog.Events;
using Serilog.Sinks.MSSqlServer;
using System.Transactions;
using var ts = new TransactionScope(asyncFlowOption: TransactionScopeAsyncFlowOption.Enabled);
var logger = new LoggerConfiguration()
.WriteTo
.MSSqlServer(
connectionString: @"Server=.\sqlserver;Database=Test;Integrated Security=SSPI;",
sinkOptions: new MSSqlServerSinkOptions { TableName = "Logs" })
.CreateLogger();
logger.Information("info");
ts.Dispose(); // Rolls back. Added for clarity. Dispose happens anyway.
每次运行都会整齐地将日志记录写入测试数据库。
此处,Logs
是 Serilog 在未配置其他任何内容时所期望的标准日志记录表:
CREATE TABLE [Logs] (
[Id] int IDENTITY(1,1) NOT NULL,
[Message] nvarchar(max) NULL,
[MessageTemplate] nvarchar(max) NULL,
[Level] nvarchar(128) NULL,
[TimeStamp] datetime NOT NULL,
[Exception] nvarchar(max) NULL,
[Properties] nvarchar(max) NULL
CONSTRAINT [PK_Logs] PRIMARY KEY CLUSTERED ([Id] ASC)
);
请注意,Serilog 建议使用静态记录器对象。