Asp.net web api +实体框架:多个请求导致数据冲突

时间:2013-12-22 13:23:31

标签: asp.net sql asp.net-mvc entity-framework

我正在使用VS613开发应用程序,使用EF6.02和Web API 2.我正在使用ASP.NET SPA模板,并针对由sql server支持的实体框架数据源创建RESTful api。 (在开发中,它驻留在SQL Server本地实例上。)

到目前为止,我有两种API方法(一种只读取数据,另一种是写入数据),我正在通过在javascript中调用它们来测试它们。当我只在我的脚本中调用一个方法时,任何一个都可以正常工作。但是如果我在脚本中调用它们(不等待任何一个回调触发),我会在调试器中得到错误的结果和不同的异常。某些例外情况表明由于存在待处理事务而无法完成保存。另一个例外说明了与其他线程的冲突。有时,在尝试读取结果集时,读操作会因空指针异常而失败。

“不允许新事务,因为会话中还有其他线程运行。”

这让我怀疑我是否正确地为每个请求获取一个新的DBContext。我的代码如下:

    static Startup()
    {
        context = new Data.SqlServer.AppDbContext();
  ...
    }

然后每当实例化一个工作单元时,我都会访问Startup.context。

我尝试实现工作单元模式,每个请求共享一个具有单个DBContext对象的UOW对象。

我的问题:我是否还有另外的责任来确保网络请求“相处得很好”?我希望这是其他人已经处理过的问题。也许我所看到的错误是合法的,如果一个用户的数据被触摸,它暂时处于无效状态,如果其他请求进入该确切时刻,它们确实会失败(我应该编码预期这些失败)。我想即使每个请求都有自己的DBContext,它们仍然共享相同的底层SQL数据源,因此可能会导致问题。

我可以尝试组合一个测试用例,但是根据我放置断点的位置以及我花费多长时间,我会得到不同的行为,再次向我重申这与时间有关。

感谢您提供任何帮助或建议...... -ben

1 个答案:

答案 0 :(得分:2)

您的问题是您设置上下文的位置。 Startup方法适用于整个应用程序启动的时间,因此所做的任何请求都将使用相同的上下文。这不是每个请求设置,而是每个应用程序设置。至于为什么会出现错误,EntityFramework NOT 是线程安全的。由于IIS生成许多线程来处理并发请求,因此您的单个context正在多个线程中使用。

至于解决方案,您可以查看

- 依赖注入框架(例如NinjectUnity

- 在UnitOfWork类中放置一个using语句

using(var context = new Data.SqlServer.AppDbContext()){//do stuff}

- 或者,我已经看到人们创建一个类的实例,该类获取该请求的上下文并将其存储在HttpContext.Cache []元素中(使用唯一的名称,以便您可以轻松地在另一个类中检索它),这样你就可以为同一个请求重用相同的上下文。像这样:

public AppDbContext GetDbContext()
    {
        var httpContext = HttpContext.Current;
        if (httpContext == null) return new AppDbContext();
        const string contextTypeKey = "AppDbContext";
        if (httpContext.Items[contextTypeKey] == null)
        {
            httpContext.Items.Add(contextTypeKey, new AppDbContext());
        }
        return httpContext.Items[contextTypeKey] as AppDbContext;
    }

要使用上述方法,请拨打简单的电话var context = GetDbContext();

注意

我们有上述所有方法,但这是第三种方法。它似乎适用于两个警告。首先,不要在using语句中使用它,因为在请求范围内(处理它)它将无法用于任何其他类。其次,确保您在Application_EndRequest上有一个实际处理它的电话。我们看到这些小虫子在请求在内存中结束后徘徊,导致内存使用量大幅增加。