Когда вызывается DbConnection.StateChange?
У меня есть следующий код:
class Program
{
static void Main()
{
var connection = new SqlConnection("myConnectionString");
connection.Open();
connection.StateChange += HandleSqlConnectionDrop;
Console.WriteLine("Hi");
Console.ReadLine();
}
private static void HandleSqlConnectionDrop(object connection, StateChangeEventArgs args)
{
Console.WriteLine("DB change detected");
}
}
Я запускаю вышеуказанный код, пока экземпляр SQL-сервера запущен. Затем я перехожу к выполнению
SHUTDOWN WITH NOWAIT;
на сервере SQL Server, к которому подключена программа. Затем я наблюдаю остановку службы SQL-сервера. Тем не менее, я никогда не вижу сообщение "обнаружено изменение БД" на выходе. Почему это?
Помимо этого: Я увижу, что обработчик StateChange вызывается, если я затем попытаюсь выполнить операцию над соединением SQL, но никогда раньше. Есть ли способ изменить это поведение?
Ответы
Ответ 1
Когда DbConnection.StateChange называется?
Вы можете узнать, посмотрев исходный код ссылки Microsoft.
Событие StateChange
вызвано функцией DbConnection.OnStateChange
. Поиск ссылок на эту функцию дает только несколько экземпляров:
Во-первых, в классе SqlConnection
OnStateChange
вызывается только в Close
.
Затем в файле DbConnectionHelper.cs
есть частичный класс под названием DBCONNECTIONOBJECT
. Похоже, что он использовался для всех DbConnection
-пределенных классов, используя некоторые махинации времени сборки. Поэтому вы можете считать его частью SqlConnection
. В любом случае он вызывает OnStateChange
только из SetInnerConnectionEvent
.
Насколько я могу судить (частичная бессмыслица класса затрудняет), SqlConnection.SetInnerConnectionEvent
вызывается только из SqlConnectionFactory.SetInnerConnectionEvent
. И это вызвано из:
Итак, в итоге - событие возникает только в ответ на действия на стороне клиента - не возникает опроса состояния подключения, встроенного в SqlConnection
.
Можно ли изменить это поведение?
Глядя на исходный код, я не вижу его. Как и другие, вы могли бы реализовать свой собственный опрос, конечно.
Ответ 2
Событие StateChange
предназначено для состояния соединения, а не для экземпляра сервера базы данных. Чтобы получить состояние сервера базы данных,
Событие StateChange происходит, когда состояние события изменяется с закрыт для открытия или открыт для закрытия.
Из MSDN: https://msdn.microsoft.com/en-us/library/system.data.common.dbconnection.statechange(v=vs.110).aspx
Если вы собираетесь катить собственный монитор для базы данных, вы можете использовать метод, который возвращает true/false, если соединение доступно, и пинг этого метода по расписанию. Вы можете даже обернуть метод, чтобы сделать это в бесконечном цикле, повторяющемся после продолжительности времени, и поднять его собственное событие, когда это "состояние" действительно изменится.
Здесь быстрый метод из другого ответа SO, который является простым подходом:
/// <summary>
/// Test that the server is connected
/// </summary>
/// <param name="connectionString">The connection string</param>
/// <returns>true if the connection is opened</returns>
private static bool IsServerConnected(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
try
{
connection.Open();
return true;
}
catch (SqlException)
{
return false;
}
}
}
Источник: fooobar.com/info/111350/...