DbContext ChangeTracker丢失Web请求中的更改。通过行动过滤器

时间:2015-11-04 13:23:44

标签: c# entity-framework asp.net-web-api2

我正在尝试创建一个UnitOfWork Action Filter。

我已经挂钩OnActionExecuted方法,我希望根据三条规则保存对DBContext的所有更改: -

  1. Context不是NULL。
  2. Context ChangeTracker HasChanges
  3. 在ActionMethods存在的整个生命周期中都没有发现异常。
  4. 在整个WEB API中的操作方法中,我只将实体附加到DbContext,它只在动作本身完成而没有任何错误时才提交更改。

    使用Ninject进行设置的DbContext,其生活方式为" InRequestScope"。

    这是UnitOfWork ActionFilterAttribute: -

    public class UnitOfWorkActionFilterAttribute : ActionFilterAttribute
        {
            public virtual IActionTransactionHelper ActionTransactionHelper
            {
                get { return WebContainerManager.Get<IActionTransactionHelper>(); }
            }
    
            public override bool AllowMultiple
            {
                get { return false; }
            }
    
            public override void OnActionExecuting(HttpActionContext actionContext)
            {
                ActionTransactionHelper.BeginTransaction();
            }
    
            public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
            {
    
                ActionTransactionHelper.EndTransaction(actionExecutedContext);
                ActionTransactionHelper.CloseSession();
            }
        }
    

    在Ninject中,DbContext的配置如下: -

    container.Bind<MyDbContext>().ToSelf().InRequestScope();
    

    这是ActionTransactionHelper类: -

    public class ActionTransactionHelper : IActionTransactionHelper
        {
    
            public bool TransactionHandled { get; private set; }
            public bool SessionClosed { get; private set; }
            public void BeginTransaction()
            {
                var sessionContext = WebContainerManager.Get<MyDbContext>();
    
                if (sessionContext == null)
                {
                    throw new NullReferenceException("sessioncontext");
                }
    
            }
    
            public async Task EndTransaction(HttpActionExecutedContext filterContext)
            {
                var sessionContext = WebContainerManager.Get<MyDbContext>();
    
                if (sessionContext != null && sessionContext.ChangeTracker.HasChanges() && filterContext.Exception == null)
                {
                   var x = await sessionContext.SaveChangesAsync();
                }
    
                TransactionHandled = true;
            }
    
            public void CloseSession()
            {
    
                var sessionContext = WebContainerManager.Get<MyDbContext>();
    
                if (sessionContext == null) return;
                sessionContext.Dispose();
    
                SessionClosed = true;
            }
        }
    

    我有一个Action方法,它将enities连接到DBContext,如下所示: -

     context.Claims.Add(entity);
    

    当在ActionExecuted上触发EndTransaction()方法时,上下文对象在ChangeTracker中没有任何更改的记录,并且永远不会触发SaveChangesAsync()方法。

    但是,如果我将DbContext的Ninject Binding更改为Singleton,代码工作正常,跟踪更改并将对象保存到数据库。

    我不明白为什么这不是每个网络请求都有效?

    在这种情况下,我不想使用Singletons。

1 个答案:

答案 0 :(得分:1)

通过添加Ninject.WeApi2 Nuget Package解决了这个问题。

在NinjectWebCommon中,我将NinjectDependencyResolver实现替换为Ninject.WeApi2中引用的实现

**Ninject.Web.WebApi.NinjectDependencyResolver**

InRequestScope()现在可以正常使用Action Filters,DBContext可以跟踪更改。