Внутренний.Ошибка поставщика данных NET framework 12
Привет,
Я постараюсь как можно лучше объяснить ошибку, которую я "иногда" получаю.
У меня есть VB.NET DLL, которая вызывается из приложения на ферме серверов, может быть, 100 пользователей, а также веб-сайт, сидящий на ферме, которая вызывает DLL.
Поскольку все мои пользователи из разных компаний, у всех них есть свои собственные базы данных, поэтому DLL запрашивает таблицу, чтобы вернуть строку подключения для соответствующей базы данных для этого пользователя.
Иногда существует множество вызовов из различных библиотек DLL, которые выполняют различные функции, но вызывают эту таблицу, чтобы получить ее connectionstring, а затем идут выполнять некоторую работу с этой базой данных, будь то вставка/обновление/удаление или выбор, а также циклические таблицы данных для обработки данных. Таким образом, существует множество подключений к SQL2000.
В настоящее время приложение также работает в VB6, и у нас никогда не было никаких проблем (более 10 лет!), но с тех пор, как я начал обновлять его до .NET 4.0, я начинаю получать
Цитата:Внутренняя ошибка поставщика данных .Net Framework 12
и
иногда указывается:
Цитата:Ссылка на объект не установлена на экземпляр объекта
что я предполагаю, вероятно, из-за неудачного соединения.
Делая различные поиски по этому вопросу, кажется, что-то связано с моим подключением DLL к базе данных SQL Server (2000) - я использую OLEDB для подключения, и результаты google, где я смотрел, похоже, указывают на потоковую обработку OLEDB, которая не очень хороша - моя DLL и другие приложения не используют потоки напрямую, но я думаю, что с ним несколько раз вызываются из приложения VB6, некоторые приложения .net win forms и несколько других приложений. vb.net это уже слишком.
Я просто не понимаю, как VB6 грамотно справляется с этим оком уже более десяти лет, а потом, когда я запускаю его vb.net он валится кучей. Когда я запускаю вещи как один пользователь или запускаю их локально на своей машине VM dev, я не получаю проблемы, это когда вещи забиваются несколькими пользователями, начинают появляться ошибки.
Любая помощь была бы очень признательна, это заставляет меня подниматься на стену, и я не знаю, где искать дальше :(
Заранее спасибо :)
Карл
УЛУЧШИТЬ ВОПРОС:
Итак, у меня есть DLL (CalculateScore), которую я вызываю из библиотеки DLL VB6, которая вызывается с классической страницы ASP. (У меня есть библиотеки DLL для фонового кодирования, так как один и тот же код используется совместно с приложением VB6 и Winforms)
Библиотека CalculateScore сначала вызывает другую библиотеку .net dll, называемую CONNMAN, которая извлекает строку подключения и возвращает ее обратно в calculatescore, чтобы знать, какую базу данных открыть на SQL Server 2000. Причина, по которой у меня есть библиотека CONNMAN dll, заключается в том, что существуют другие библиотеки DLL, которые вызывают эту библиотеку DLL для возврата соответствующей строки подключения.
Функция CALCULATESCORE DLL открыла Connman:
Public Function OpenPassConnection(ByVal CorporationID As String, ByVal TestProj As Boolean) As Boolean Try Dim NewConn As New Connman.ConnMan myConnectionString = NewConn.ReturnConnectionString(P3AddON_CORPID) NewConn = Nothing If myConnectionString <> "" Then GConn = New OleDb.OleDbConnection GConn.ConnectionString = myConnectionString GConn.Open() End If Catch ex As Exception Using sw As IO.StreamWriter = IO.File.AppendText(System.IO.Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location) & "\PASS4_CALCSCORE" & CorporationID & "_errorlog.txt") sw.WriteLine(Now & " - OpenPassConnection - " & ex.Message) End Using ' Windows.Forms.MessageBox.Show("OpenPassConnection:" & Err.Description, "Pass4", Windows.Forms.MessageBoxButtons.OK, Windows.Forms.MessageBoxIcon.Error) Return False End Try Return True End Function
Эта библиотека dll "CONNMAN" открывается следующим образом:
resultstr=
OpenPassConnection(ByVal CorporationID As String) As String
Функция просматривает текстовый файл в текущем каталоге, чтобы установить соединение с базой данных SQL Server 2000, содержащей записи по каждой компании, и возвращает строку соединения из поля, а затем открывает соединение и выполняет некоторую работу (я вставлю это после этой функции ниже):
Public Function OpenPassConnection(ByVal CorporationID As String) As String Dim myConnectionString As String = "" Dim Pass4DBConnectionStr As String = "" Dim SQLStr As String Dim path As String = System.IO.Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location) & "\Connection\ConnStr.txt" Try If FileIO.FileSystem.FileExists(path) = False Then Return "Unable to find file:" & path End If Dim sr As StreamReader = New StreamReader(path) myConnectionString = sr.ReadLine() sr.Close() If myConnectionString <> "" Then Gconn = New OleDb.OleDbConnection Gconn.ConnectionString = myConnectionString Gconn.Open() End If ' Now lets get the main connectionstring for the database and return it SQLStr = "SELECT [ServerDBConnString] FROM [Pass4_Connections] WHERE [CorpID]='" & FixsQuote(CorporationID) & "'" Pass4DBConnectionStr = GetAnyDetail(CorporationID, SQLStr, "ServerDBConnString", "") Catch ex As Exception Return "ERROR:" & ex.Message End Try Return Pass4DBConnectionStr End Function
поэтому когда строка соединения возвращается в CalculateScore и открывает это соединение и получает этот бит кода:
SQLstr = "SELECT CREATE_PERCENT,impacts,propertyref,subjective,increase_improve,mechanism,[assessmentsummary].* from [questionheading] inner join [assessmentsummary] on [questionheading].[questionheadingref]=[assessmentsummary].questionheadingref where [assessmentsummary].assessmentsummaryref=" & AssRef da = New OleDb.OleDbDataAdapter(SQLstr, GConn) ds = New DataSet da.Fill(ds, "GettingItem") If ds.Tables(0).Rows.Count = 0 Then da.Dispose() ds.Dispose() da = Nothing ds = Nothing Using sw As IO.StreamWriter = IO.File.AppendText(System.IO.Path.GetDirectoryName(Reflection.Assembly.GetExecutingAssembly().Location) & "\PASS4_" & CorporationID & "_errorlog.txt") sw.WriteLine(Now & " - NO RECORDS ERROR") End Using Return "No Records, ERROR" End If
Если я вызываю этот код через приложение winforms, отлаживаю и выполняю его, я не получаю никаких ошибок. "иногда" он падает на этот код с (различными ошибками, в зависимости от того, насколько интенсивно используется):
ExecuteReader requires an open and available Connection. The connection's current state is connecting.
Internal .Net Framework Data Provider error 12.
Object reference not set to an instance of an object.
Просмотр этих ошибок (в частности, текущее состояние подключения) привел меня к тому, что вы упомянули об «Использование» и «Завершение использования» - теперь я могу заключить все в это, вместо того, чтобы открывать глобальную функцию, но я действительно использую .close .dispose и = ничего в конце моего использования (я довольно ОКР, чтобы убедиться, что я закрываю вещи после того, как он был открыт), но может ли кто-нибудь сказать мне <
Что я уже пробовал:
Я обнаружил, что в VB6 мои библиотеки DLL являются "квартирными потоками" - в VB6 такой опции нет. VB.NET studio 2015-я думаю, мне нужно сделать мои библиотеки DLL квартирно-резьбовыми-я не слишком беспокоюсь о производительности, так как у меня не было никаких проблем с настройкой VB6, мне просто нужно устранить свою проблему
Richard MacCutchan
Ссылка на объект, не установленная на экземпляр объекта, означает, что у вас где-то есть ошибка, которая не была обнаружена в VB6. И из того, что вы написали выше, вполне возможно, что это имеет какое-то отношение к Мутли-потоку. Вполне возможно, что ваш код не является потокобезопасным. Но единственный способ узнать это-много отлаживать.
Member 12561559
Я знаю, что код работает, так как он отлично работает локально. Единственное, что я вижу, что часто встречается там, где происходят ошибки, и я не знаю, имеет ли это значение или нет, поскольку он отлично работал в VB6 и отлично работал локально, - это то, что я передаю oledb.connection через параметр функции. Я раздену их и глобально объявлю соединение oledb. Обновит этот поток, если это его разберет. Хотя Спасибо, что перезвонили мне, очень ценю.
Richard MacCutchan
- Подожди! Прежде чем что-то менять, вы должны быть уверены, что проблема именно в этом. Просто потому, что что-то работает в VB6, это не значит, что оно не содержит ошибок. Возможно, VB6 просто маскирует проблему.
Karthik_Mahalingam
Это общая ошибка, используйте отладчик, чтобы точно указать на ошибку.
Member 12561559
Я знаю, что код работает, так как он отлично работает локально. Единственное, что я вижу, что часто встречается там, где происходят ошибки, и я не знаю, имеет ли это значение или нет, поскольку он отлично работал в VB6 и отлично работал локально, - это то, что я передаю oledb.connection через параметр функции. Я раздену их и глобально объявлю соединение oledb. Обновит этот поток, если это его разберет. Хотя Спасибо, что перезвонили мне, очень ценю.
Richard Deeming
Это звучит так, как будто Вы делитесь одним OleDbConnection
объект через несколько вызовов. Это не очень хорошая идея - класс не был разработан, чтобы быть потокобезопасным, и вы в конечном итоге испортите его внутреннее состояние, что приведет к странным ошибкам.
Вместо этого вы должны создать OleDbConnection
когда вам это нужно, и положите его в Using
блок, чтобы убедиться, что он будет утилизирован должным образом.
Эта проблема не возникла бы с VB6, потому что VB6 был в основном однопоточным.
Но сейчас мы можем только догадываться, в чем проблема, потому что вы не поделились ни одним своим кодом. Если вам нужен более конкретный совет, нажмите кнопку "улучшить вопрос" и добавьте к нему соответствующие части вашего кода.
Member 12561559
Спасибо Ричарду, я обновил вопрос - другие поиски также привели меня к оператору Using - если вы не возражаете против ответа на то, что я сделал - я, вероятно, использую старые плохие привычки из VB, и хотя он работает в .NET, он не работает "хорошо". Спасибо - я очень ценю то время, которое вы тратите на ответы.
Member 12561559
Не могли бы вы ответить еще на один вопрос - больше для моего здравомыслия, чем для чего-либо.
Я преобразовал свой код так, что у меня нет публичного oledb-соединения, но вместо этого я использую блок USING для открытия и выполнения некоторой работы - однако мне нужно вызвать другие функции в моей DLL и заставить его передать oledb-соединение, открытое в операторе USING, через эти функции - будет ли это держать его потокобезопасным или мне нужно сделать больше, используя блоки в этих отдельных функциях, чтобы открыть новое соединение и закрыть его, когда оно будет завершено?
Richard Deeming
Это должно быть прекрасно. Вам нужно только беспокоиться, если вы храните объект соединения в поле. Если вы передаете его в качестве параметра, он почти всегда будет локальным для текущего потока.
Member 12561559
Идеальный. Вы очень помогли мне, Ричард, большое спасибо.