首页 新闻 会员 周边 捐助

【高分】DbCommandInterceptor内部使用EF上下文记录日志如何防止死循环?

0
悬赏园豆:10 [已解决问题] 解决于 2017-07-03 18:21

 如题,需要对拦截到的ef语句进行数据库入库操作, 

我调试发现,currentDB.Entry(aLog).State = EntityState.Added; currentDB.Set<AuditLog>().Add(aLog); currentDB.SaveChangesAsync(); 并没有发生死循环。

但是这个没报错 也没有插入数据库。不知道为什么

复制代码
/// <summary>
    /// 数据库执行拦截
    /// </summary>
    public class EFIntercepterLogging : DbCommandInterceptor
    {
       
        private readonly Stopwatch _stopwatch = new Stopwatch();  

        public override void ScalarExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            base.ScalarExecuting(command, interceptionContext);  
            _stopwatch.Restart();
        }
        public override void ScalarExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        { 
            _stopwatch.Stop();
            AuditLog aLog = InitLog(command);
            IDbContext currentDB = (IDbContext)interceptionContext.DbContexts.Where(q => q.GetType() == typeof(EFContext)).FirstOrDefault();
            if (aLog != null)
            {
                if (interceptionContext.Exception != null)
                {
                    aLog.SqlQuery = (string.Format("Exception:{1} \r\n --> Error executing command: {0}", command.CommandText, interceptionContext.Exception.ToString()));
                }
                else
                {
                    aLog.SqlQuery = (string.Format("\r\n执行时间:{0} 毫秒\r\n-->ScalarExecuted.Command:{1}\r\n", _stopwatch.ElapsedMilliseconds, command.CommandText));
                }

                if (currentDB != null)
                {
                     
                    currentDB.Entry(aLog).State = EntityState.Added;
                    currentDB.Set<AuditLog>().Add(aLog);
                    currentDB.SaveChangesAsync();
                }
            }

            base.ScalarExecuted(command, interceptionContext);
        }
        public override void NonQueryExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            base.NonQueryExecuting(command, interceptionContext);
            _stopwatch.Restart();
        }
        public override void NonQueryExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            _stopwatch.Stop();
            AuditLog aLog = InitLog(command);
            IDbContext currentDB = (IDbContext)interceptionContext.DbContexts.Where(q => q.GetType() == typeof(EFContext)).FirstOrDefault();
            if (aLog != null)
            {
                if (interceptionContext.Exception != null)
                {
                    aLog.SqlQuery = (string.Format("Exception:{1} \r\n --> Error executing command:\r\n {0}", command.CommandText, interceptionContext.Exception.ToString()));
                }
                else
                {
                    aLog.SqlQuery = (string.Format("\r\n执行时间:{0} 毫秒\r\n-->NonQueryExecuted.Command:\r\n{1}", _stopwatch.ElapsedMilliseconds, command.CommandText));
                }
                if (currentDB != null)
                { 
                    currentDB.Entry(aLog).State = EntityState.Added;
                    currentDB.Set<AuditLog>().Add(aLog);
                    currentDB.SaveChangesAsync();
                }
            }

            base.NonQueryExecuted(command, interceptionContext);
        }
        public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {
            base.ReaderExecuting(command, interceptionContext);
            _stopwatch.Restart();
        }
        public override void ReaderExecuted(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {
            _stopwatch.Stop();
            IDbContext currentDB = (IDbContext)interceptionContext.DbContexts.Where(q=>q.GetType() == typeof(EFContext)).FirstOrDefault();
              
            AuditLog aLog = InitLog(command);
            if (aLog != null)
            {
                if (interceptionContext.Exception != null)
                {
                    aLog.SqlQuery = (string.Format("Exception:{1} \r\n --> Error executing command:\r\n {0}", command.CommandText, interceptionContext.Exception.ToString()));
                }
                else
                {
                    aLog.SqlQuery = (string.Format("\r\n执行时间:{0} 毫秒 \r\n -->ReaderExecuted.Command:\r\n{1}", _stopwatch.ElapsedMilliseconds, command.CommandText));
                }
                //repo.Insert<AuditLog>(aLog);
                //repo.SaveChanges();

                if (currentDB != null)
                { 
                    currentDB.Entry(aLog).State = EntityState.Added;
                    currentDB.Set<AuditLog>().Add(aLog);
                    currentDB.SaveChangesAsync(); 
                }
            }

            base.ReaderExecuted(command, interceptionContext);
        }

        private AuditLog InitLog(System.Data.Common.DbCommand command)
        {
            AuditLog log = new AuditLog();

            HttpContextBase context = new HttpContextWrapper(HttpContext.Current);
            RouteData rd = RouteTable.Routes.GetRouteData(context);
            if (rd != null)
            {
                string controllerName = rd.GetRequiredString("controller");
                string actionName = rd.GetRequiredString("action");
                string userName = HttpContext.Current.User.Identity.Name;
                string parms = "";
                if(command!=null)
                {
                   foreach(DbParameter parm in command.Parameters)
                    {
                        parms += string.Format(" 参数名:{0},值:{1};",parm.ParameterName,parm.Value);
                    }
                }


                //排除审计控制器自身 以及日志插入自身
                if (actionName.Contains(SystemConsts.ExceptedController_Audit)
                    || command.CommandText.Contains(SystemConsts.ExceptedTable_AuditLog))
                    return null;

                log.Controller = controllerName;
                log.Action = actionName;
                log.StartTime = DateTime.Now;
                log.EndTime = DateTime.Now;
                log.AuditAccount = userName;
               // log.IP = IPHelper.GetRealIP();
                log.Parameters = parms; 
            }
            return log;
        }
    }
复制代码
王庆东mas的主页 王庆东mas | 初学一级 | 园豆:4
提问于:2017-06-27 14:39
< >
分享
最佳答案
0

分好高。。。。。。

你在 NonQueryExecuted里面  

currentDB.Set<AuditLog>().Add(aLog); currentDB.SaveChangesAsync();

那SaveChangesAsync又触发NonQueryExecuted,又接着插入,又触发。不就死循环拉。对不

收获园豆:10
czd890 | 专家六级 |园豆:14488 | 2017-06-27 15:50

 有解决办法吗?求指点

王庆东mas | 园豆:4 (初学一级) | 2017-06-27 16:54

@王庆东mas: 

伪代码:

if(current thread data .xx==true)

return;

current thread data .xx=true

currentDB.SaveChangesAsync();

currentthread data.xx=false

czd890 | 园豆:14488 (专家六级) | 2017-06-27 16:59

@czd890: 我调试发现,currentDB.Entry(aLog).State = EntityState.Added; currentDB.Set<AuditLog>().Add(aLog); currentDB.SaveChangesAsync(); 并没有发生死循环。

但是这个没报错 也没有插入数据库。不知道为什么。

大神可以把我代码 复制了去帮我试下 ,呵呵

王庆东mas | 园豆:4 (初学一级) | 2017-06-27 17:10

@王庆东mas: 

 

还有这种语句。ExecuteSqlCommandAsync。在然后。不要用async测试。异步了。

czd890 | 园豆:14488 (专家六级) | 2017-06-27 17:13

@czd890: 没懂哈,问题依旧没解决==,不知道是拿到的CurrentDb 是还没打开连接还是啥?

王庆东mas | 园豆:4 (初学一级) | 2017-06-27 17:14

@王庆东mas: 

 

if(current thread data .xx==true)

return;

current thread data .xx=true

currentDB.ExecuteSqlCommand("insert into auditlog values ('s','3','ff')", null);

currentDB.SaveChanges();

currentthread data.xx=false

czd890 | 园豆:14488 (专家六级) | 2017-06-27 17:17

@czd890: 不是死循环问题阿啊啊啊。不信你测试

王庆东mas | 园豆:4 (初学一级) | 2017-06-27 17:18

@王庆东mas: 

不是死循环,能堆栈溢出啊,也是醉了

czd890 | 园豆:14488 (专家六级) | 2017-06-27 17:20

@czd890: 堆栈溢出是因为:currentDB.ExecuteSqlCommand(" delete from auditlog ", new object[] { });我把他删了。

问题是这个:

我调试发现,currentDB.Entry(aLog).State = EntityState.Added; currentDB.Set<AuditLog>().Add(aLog); currentDB.SaveChangesAsync(); 并没有发生死循环。

但是这个没报错 也没有插入数据库。不知道为什么

--

哎---

王庆东mas | 园豆:4 (初学一级) | 2017-06-27 17:21

@王庆东mas: currentDB.SaveChanges();

czd890 | 园豆:14488 (专家六级) | 2017-06-27 17:23

@czd890: 未解决。。你把代码复制一下 试试就知道了。

王庆东mas | 园豆:4 (初学一级) | 2017-06-27 17:27

@王庆东mas: 

代码copy做个demo出来呀

czd890 | 园豆:14488 (专家六级) | 2017-06-27 17:28
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册