在Using语句中创建ObjectContext时出现了NullReferenceException异常

12

又到了请教高手的时候了。

我遇到了一个很奇怪的现象。正如标题所述,当我尝试创建一个 EF ObjectContext 时,如果我在 Using 语句中创建上下文,我会得到 NullReferenceException 异常。我尝试了各种不同的方法,但结果总是一样。当然,这段代码昨天之前都能够正常工作。可能与我昨天早上运行的 Windows 更新有关。

无论如何...

如果我尝试这样做

using (var context = new Entities(Env.Instance.Connection))
{
    //do a bunch of EF stuff
}
我在创建我的ObjectContext时遇到了NullReferenceException。这里的Env.Instance.Connection是在程序早期创建的EntityConnection。我已经逐步检查以确保实例和EntityConnection都存在。
如果我这样做
var context = new Entities(Env.Instance.Connection);
//do a bunch of EF stuff
context.Dispose();

一切都正常。

我已经尝试过。

using (var context = new Entities(Env.Instance.ConnectionName)) //the name of a connection string in my App.Config
{
    //do a bunch of EF stuff
}

我已经尝试过了

using (var context = new Entities(Env.Instance.ConnectionString)) //the actual connection string
{
    //do a bunch of EF stuff
}

我甚至尝试过

using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
{
    //do a bunch of EF stuff
}

无所谓。如果我在using语句内创建上下文,我总是会收到NullReferenceException。

我可以进入我的数据层代码并退出ObjectContext构造函数。

public Entities(string connectionString) : base(connectionString, "Entities")
{
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
}

但是,一旦我退出构造函数,就会抛出错误。

有什么想法?

编辑

在最简单的迭代中,堆栈跟踪如下:

在C:\SVN\IkaPlus\IkaPlus\ViewModel\MainVM.cs:Line 1371处的IkaPlus.ViewModel.MainVM.ProcessMail3(Object sender, DoWorkEventArgs e)
在C:\SVN\IkaPlus\IkaPlus\ViewModel\MainVM.cs:Line 832处的IkaPlus.ViewModel.MainVM.RefillQueues()。

理想情况下,ProcessMail3应该由BackgroundWorker调用,因此它的签名是这样的,但目前,我正在使用空参数从主线程调用它。

澄清一下,ProcessMail3方法旨在从后台工作程序中调用,这就是为什么它的签名中有sender和DoWorkEventArgs。但是目前,我像这样直接从主线程调用它:ProcessMail3(null,null)

我认为rism的想法很有道理。如果我这样做

private void RefillQueues()
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    ProcessMail3(null, null);
}

private void ProcessMail3(object sender, DoWorkEventArgs e)
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }
}
RefillQueues中的using语句有效,但ProcessMail3中的using语句无效。 编辑2 为了进一步简化问题,我已经从有问题的方法签名中删除了参数。现在我正在调用:
private void RefillQueues()
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    ProcessMail3();
}

private void ProcessMail3()
{
    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }
}

同样的结果。在第一个方法中使用语句是有效的。在第二种方法中使用语句会抛出NullReferenceException异常。没有BackgroundWorkers在运行。

编辑3

所以,我似乎已经找到了导致错误的原因,尽管我仍然无法解释它。

我的ProcessMail3方法实际上看起来像这样(我将其重命名为EatCookies,因为...我喜欢吃饼干)。

private void EatCookies()
{
    #region Empty the Queue

    string s = "Queue 3";

    CicConnector.CreateInstance(SettingsHandler.Instance.CIC_PASSWORD,
              "MYSERVER",
              "C:\\temp");

    //Do a bunch of stuff

    #endregion

    #region EF Stuff

    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    #endregion
}

由于我输入方法时一直在步进,所以我没有费心去包含其他代码行。我发现,如果我注释掉创建 CiCConnector 的那行代码(不应该相关),那么之后的 using 语句就能正常运行了。即使我实际上没有到达那行代码,只要这行代码没有被注释,using 语句就无法工作。如果我在创建字符串的那行代码上设置断点,然后跳过下一行代码,直接到达 using 语句,那么我就会得到 NullReferenceException 异常。如果我注释掉 CiCConnector 那行代码并做同样的事情,则 using 语句可以正常使用。另外,如果不用 using 语句而是手动创建 ObjectContext,然后稍后手动释放它,那么不管有没有 CiCConnector 那行代码,所有东西都可以正常运行。这一切都非常奇怪。

第四次编辑

奇怪的是,如果把 CiCConnector 放在第一个方法中,它就不会引起奇怪的行为。因此,如果我这样做

private void RefillQueues()
{
    string s = "Queue 3";

    CicConnector.CreateInstance(SettingsHandler.Instance.CIC_PASSWORD,
              "MYSERVER",
              "C:\\temp");

    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }

    EatCookies();
}

private void EatCookies()
{
    string s = "Queue 3";

    CicConnector.CreateInstance(SettingsHandler.Instance.CIC_PASSWORD,
              "MYSERVER",
              "C:\\temp");

    using (var context = new Entities("metadata=res://*/MyDB.csdl|res://*/MyDB.ssdl|res://*/MyDB.msl;provider=System.Data.SqlClient;provider connection string=\"data source=MY-DB;initial catalog=MY-DB-PROD;persist security info=True;user id=dbuser;password=dbpass;multipleactiveresultsets=True;App=EntityFramework\""))
    {
    }
}

第一种方法中的using语句工作正常,但在第二种方法中它会出问题。

耸肩你的猜测和我的一样好。可能更好。我想我会把它归结为一个奇怪的事情,并简单地不使用using语句。但是,如果有人有任何见解,我会很高兴知道到底发生了什么。


2
调用栈是什么? - Justin Harvey
堆栈跟踪未显示任何空引用异常,你确定这就是全部吗? - Justin Harvey
我认为我们不知道这里的null是什么。你说“我可以进入我的数据层代码,然后退出ObjectContext构造函数”->所以上下文不是null..也许看到源代码的其他部分会有所帮助。顺便说一句,using编译成一个try{}finally{context.Dispose()}块。 - gregkalapos
是的,内部异常为空。@rism 我传入null是因为方法签名要求两个参数。我尝试将该方法更改为private void ProcessMail3()并且不带任何参数调用它,但结果相同。 - Troy Frazier
有没有可能 OnContextCreated 在某个地方干扰了? - Gert Arnold
显示剩余9条评论
1个回答

1
EF会为您管理处理,因此自己使用using或显式释放它有些多余。

http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext.html

文章片段:

在与EF团队的开发人员交谈之前,我的回答总是肯定的“当然可以!”。 但对于DbContext来说并非如此。 您不需要在DbContext对象上严格调用Dispose。即使它实现了IDisposable接口,但仅出于某些特殊情况下您才能调用Dispose作为保障。 默认情况下,DbContext会自动管理连接。 阅读到最后以了解完整的故事并看看EF团队的意见。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接