NullReferenceException при создании ObjectContext в операторе Using

Время еще раз обратиться к более высоким умам.

Я наблюдаю очень странное явление. Как указано в заголовке, я получаю NullReferenceException при попытке создать EF ObjectContext, но я получаю исключение только в том случае, если я создаю контекст в операторе Using. Пробовал разными способами, но всегда одно и то же. И, конечно же, это код, который отлично работал до вчерашнего дня. Возможно, это связано с тем, что мое обновление Windows запустилось вчера утром.

Так или иначе...

Если я попробую это

using (var context = new Entities(Env.Instance.Connection))
{
    //do a bunch of EF stuff
}

Я получаю NullReferenceException при создании моего ObjectContext. Здесь 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
}

Не имеет значения. Если я создаю контекст в операторе использования, я всегда получаю исключение NullReferenceException.

Я могу войти в код своего уровня данных и выйти из конструктора ObjectContext.

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

Но как только я выхожу из конструктора, вылетает ошибка.

Мысли?

ИЗМЕНИТЬ

В самой простой итерации трассировка стека выглядит так

в IkaPlus.ViewModel.MainVM.ProcessMail3(отправитель объекта, DoWorkEventArgs e) в C:\SVN\IkaPlus\IkaPlus\ViewModel\MainVM.cs:Line 1371.
в IkaPlus.ViewModel.MainVM.RefillQueues() в C: \SVN\IkaPlus\IkaPlus\ViewModel\MainVM.cs:строка 832.

В идеале 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\""))
    {
    }
}

Оператор using в RefillQueues работает, а оператор using в ProcessMail3 — нет.

ИЗМЕНИТЬ 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. Нет запущенных фоновых рабочих.

ИЗМЕНИТЬ 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
}

Я не удосужился включить другие строки кода, потому что я перешагивал через них, когда вводил метод. Voodoo teching, я обнаружил, что если я закомментирую строку, которая создает мой CiCConnector (не должно иметь значения), мой оператор использования после того, как он будет работать нормально. Если строка НЕ ​​закомментирована, независимо от того, дошел ли я до этой строки кода или нет, оператор using не работает. Если я устанавливаю точку останова в строке, где я создаю свою строку, и пропускаю следующую строку, переходя непосредственно к моему оператору использования, я получаю исключение NullReferenceException. Если я закомментирую строку CiCConnector и сделаю то же самое, оператор using сработает. И опять же, если вместо оператора using я просто создаю свой ObjectContext, а затем удаляю его вручную, все это работает нормально, независимо от строки CiCConnector. Все это очень странно.

ИЗМЕНИТЬ 4

Как ни странно, строка 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. Но, если у кого-то есть понимание, я был бы рад узнать, что, черт возьми, здесь происходит.


person Troy Frazier    schedule 12.11.2015    source источник
comment
Что такое стек вызовов?   -  person Justin Harvey    schedule 12.11.2015
comment
Согласно @JustinHarvey, простого блока try catch с точкой останова в catch должно быть достаточно для решения проблемы.   -  person rism    schedule 12.11.2015
comment
Попробуйте очистить решение, закрыть визуальную студию и снова открыть ее и перестроить, посмотрите, поможет ли это :)   -  person User2012384    schedule 12.11.2015
comment
@JustinHarvey Я обновил вопрос с помощью трассировки стека. rism Это уже в блоке try-catch User2012384 Я пробовал. Я очистил решение, перезапустил VS, даже перезагрузил компьютер. Не повезло.   -  person Troy Frazier    schedule 12.11.2015
comment
Трассировка стека не показывает никаких исключений null ref, вы уверены, что это все?   -  person Justin Harvey    schedule 12.11.2015
comment
@JustinHarvey StackTraces не показывает тип исключения. Просто складывайте кадры. то есть местоположение.   -  person rism    schedule 12.11.2015
comment
@TroyFrazier С вашим редактированием вы перешли от «Я не могу создать объектный контекст» к множеству других вещей, которые могут включать проблемы с потоками в зависимости от остальной части вашего кода. Вам нужно сузить проблемное пространство. Что показывает ваша трассировка стека, так это то, что ошибка не появляется в конструкторе вашего класса Entities, иначе он будет иметь что-то вроде Entities..ctor. Запустите только этот using (var context = new Entities(Env.Instance.ConnectionString)) { // do nothing } из чистого/обычного метода. Если он работает нормально, это не блок использования, а метод, в котором вы находитесь.   -  person rism    schedule 12.11.2015
comment
Я думаю, мы не знаем, что здесь нулевое. Вы говорите, что я могу войти в код своего уровня данных, и я выхожу из конструктора ObjectContext -> поэтому контекст не равен нулю. Возможно, просмотр других частей исходного кода поможет. Кстати. использование компилируется в блок try{}finally{context.Dispose()}.   -  person gregkalapos    schedule 12.11.2015
comment
Вышеприведенное также предполагает, что innerException равно нулю... в противном случае, конечно, сначала посмотрите туда.   -  person rism    schedule 12.11.2015
comment
@rism Я не верю, что это проблема с потоками. Как я уже сказал, метод ProcessMail3 предназначен для вызова из фонового исполнителя, поэтому в его подписи есть sender и DoWorkEventArgs. Но на данный момент я вызываю его прямо из основного потока, например: ProcessMail3(null, null)   -  person Troy Frazier    schedule 12.11.2015
comment
Сам факт того, что вы передаете нули методу, предназначенному для вызова из фонового потока, и получаете NullReferenceException, должен быть довольно сильной подсказкой. Как я уже сказал выше, просто исключите это с помощью быстрого рефакторинга или иного модульного теста.   -  person rism    schedule 12.11.2015
comment
Да, внутреннее исключение равно null @rism. Я передаю нули, потому что сигнатура метода запрашивает два параметра. Я попытался изменить метод на private void ProcessMail3() и вызвать его без каких-либо параметров, и я получаю те же результаты.   -  person Troy Frazier    schedule 12.11.2015
comment
Если сменить подпись на private void ProcessMail2(), получится? Или private void Processxyz()   -  person rism    schedule 12.11.2015
comment
Есть вероятность, что OnContextCreated где-то мешает?   -  person Gert Arnold    schedule 18.11.2015


Ответы (1)


EF управляет утилизацией за вас, поэтому использование или явное удаление ее самостоятельно может быть излишним.

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

Фрагмент из статьи

До того, как я поговорил с разработчиками из команды EF, мой ответ всегда был громким «конечно!». Но это не так с DbContext. Вам не нужно быть религиозным в отношении вызова Dispose для ваших объектов DbContext. Несмотря на то, что он реализует IDisposable, он реализует его только для того, чтобы вы могли вызывать Dispose в качестве защиты в некоторых особых случаях. По умолчанию DbContext автоматически управляет подключением. Дочитайте до конца, чтобы услышать всю историю и узнать, что об этом говорят разработчики EF.

person Steven Ackley    schedule 18.11.2015