I want check my SQL server connection before to connect with DB, and I need to update the status of SQL Server connection in my GUI.
Here is the code I am checking SQL connection, but I couldn't able to get status frequently
Scenario :
Stop the sql server service from services window
Running the project and will show status "Connection Not Available"
Start Sql server service and displaying "Connection Live"
And Again Stop SQL server service and i am not getting the status as ""Connection Not
Available". It's returning status as "Connection Live"
It's not getting to the catch block
Code:
private void timer1_Tick(object sender, EventArgs e)
{
bool Flag = false;
try
{
using (SqlConnection con = new SqlConnection(strcon))
{
con.Open();
}
}
catch (SqlException s)
{
Flag = true;
label1.Text = "Connection Not available";
}
finally
{
if (Flag == false)
{
label1.Text = "Connection Live";
}
}
}
If there server is unavailable, your application will hang while it tries to connect. This should be run in a background worker and the status updated with a callback.
Wrap your connection attempt in a try..catch (it should be using a using statement at the very least). [The precise location of a try..catch in your code depends somewhat on the structure of your code.]
It is unusual for an application to maintain whether a SQL Server is available. After all, it might be unavailable milliseconds after you test and display that it is available.
Related
I have code here where the connection does connect, but I keep looping to get to know if the connection is no longer available (i.e. if a SQL Server database is no longer available).
I open a connection and subscribe to the StateChange event of the connection.
If within 60 seconds (time of the transaction), I manually take the SQL Server database offline or stop the SQL Server service, even then the connection state changed event is not called.
So how does one get to know in real time if the SQL Server database or SQL Server Service is unavailable, or the connection has been lost?
NOTE: I run this script on SQL Server SSMS within 60 seconds to take the database offline.
USE master
GO
ALTER DATABASE [databaseName]
SET OFFLINE WITH ROLLBACK IMMEDIATE
GO
This is the code in C#:
private void button10_Click(object sender, EventArgs e)
{
var options = new TransactionOptions()
{
IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead,
Timeout = TimeSpan.FromSeconds(60)
};
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
{
using (SqlConnection con = new SqlConnection("Connection String"))
{
con.Open();
con.StateChange += new StateChangeEventHandler(OnConnectionStateChanged);
while (true)
{
Application.DoEvents();
}
}
}
}
private void OnConnectionStateChanged(object sender, StateChangeEventArgs args)
{
MessageBox.Show("Connection state was changed.");
}
If I am looping and waiting, even if the SQL Server database is taken offline, I am not notified by SqlConnection.StateChange.
NOTE: The continuous while loop is just to emulate any processes in the transaction, to check if connection state gets fired or not.
StateChange event will never get fired because is meant for the state of the connection, not for the instance of the database, so it wouldn't work as a health check to see if your database is up.
From the docs:
The StateChange event occurs when the state of the connection changes from closed to opened or from opened to closed.
I'm not aware of the architecture of this application, but maybe a Database Probe could help you here.
Alternatively, you could run something like this:
private static bool IsServerConnected(string connectionString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
try
{
connection.Open();
return true;
}
catch (SqlException)
{
return false;
}
}
}
Where you could throw a custom exception instead of returning false if that is what you need.
Hope this helps!
At the start of my application, I'm successfully able to check if SQL Server is running, if its not running start the specific service and then check if a particular database is connected. But I want to learn how to check if the database is connected at a timed interval.If the database gets disconnected i.e if the database gets deleted or renamed at the backend while application is running then the application should automatically terminate. How best I can achieve this?
How to call the Database is connected function at intervals? If its not connected it should terminate the application.
namespace CLearning
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
bool isServiceRunning = false;
// Applying the required visual styles - we need to do it before we display any single form on the screen.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Check specific SQL Server and database is running
isServiceRunning = DataAccessContext.CheckSQLServiceStatus();
if (isServiceRunning)
{
//SQL is running, checking for Local DB connection
bool isLocalDAOConnected = DataAccessContext.CheckIsLocalDAOConnected();
if (!isLocalDAOConnected)
{
MessageBox.Show(
"Database connection is not available on the machine. The application will termiante.",
"No database connection available",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}
Application.Run(new Form1());
}
}
}
}
The DataAccess class that checks if the server is running and database is connected is here
namespace CLearning.DataAccess
{
public class DataAccessContext
{
private static bool _isSQLServiceRunning = false;
private static bool _isLocalDAOConnected = false;
public static bool CheckSQLServiceStatus()
{
string myServiceName = "MSSQL$CLearning"; //service name of SQL Server Express
string status; //service status (For example, Running or Stopped)
//service status: For example, Running, Stopped, or Paused
ServiceController mySC = new ServiceController(myServiceName);
try
{
status = mySC.Status.ToString();
}
catch (Exception ex)
{
MessageBox.Show("SQL Service not found. It is probably not installed, application will terminate. [exception=" + ex.Message + "]");
return _isSQLServiceRunning;
}
//service status: For example, Running, Stopped, or Paused
_isSQLServiceRunning = true;
//if service is Stopped or StopPending, you can run it with the following code.
if (mySC.Status.Equals(ServiceControllerStatus.Stopped) | mySC.Status.Equals(ServiceControllerStatus.StopPending))
{
try
{
mySC.Start();
var timeout = new TimeSpan(0, 0, 5);
mySC.WaitForStatus(ServiceControllerStatus.Running,timeout);
_isSQLServiceRunning = true;
}
catch (Exception ex)
{
MessageBox.Show("Error in starting the service: " + ex.Message);
_isSQLServiceRunning = false;
}
}
return _isSQLServiceRunning;
}
public static bool CheckIsLocalDAOConnected()
{
try
{
GlobalConfig.Connection.TestConnection(); //SQL QUERY That checks for openning the connection
return _isLocalDAOConnected = true;
}
catch (Exception)
{
return _isLocalDAOConnected;
}
}
}
}
Please guide.
Thanks
AA
Check that the database is available every three minutes?
From your status thread, do this every three minutes:
Open a connection to the database server.
Set the connection to nonblocking reads with SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Do a raw query of the form SELECT TOP 1 somecolumn FROM a_key_table;
Close the connection.
Do all that stuff in a try{}catch(){} block. If you get an exception, your database has failed in the way that matters -- you can't read a row from one of your application's important tables.
The exception will tell you what went wrong (if you care): connection timeout, authentication failure, cannot read table, etc.
I use MongoDB drivers to connect to the database. When my form loads, I want to set up connection and to check whether it is ok or not. I do it like this:
var connectionString = "mongodb://localhost";
var client = new MongoClient(connectionString);
var server = client.GetServer();
var database = server.GetDatabase("reestr");
But I do not know how to check connection. I tried to overlap this code with try-catch, but to no avail. Even if I make an incorrect connectionString, I still can not get any error message.
To ping the server with the new 3.0 driver its:
var database = client.GetDatabase("YourDbHere");
database.RunCommandAsync((Command<BsonDocument>)"{ping:1}")
.Wait();
There's a ping method for that:
var connectionString = "mongodb://localhost";
var client = new MongoClient(connectionString);
var server = client.GetServer();
server.Ping();
full example for 2.4.3 - where "client.GetServer()" isn't available.
based on "Paul Keister" answer.
client = new MongoClient("mongodb://localhost");
database = client.GetDatabase(mongoDbStr);
bool isMongoLive = database.RunCommandAsync((Command<BsonDocument>)"{ping:1}").Wait(1000);
if(isMongoLive)
{
// connected
}
else
{
// couldn't connect
}
I've had the same question as the OP, and tried every and each solution I was able to find on Internet...
Well, none of them worked to my true satisfaction, so I've opted for a research to find a reliable and responsive way of checking if connection to a MongoDB Database Server is alive. And this without to block the application's synchronous execution for too long time period...
So here are my prerequisites:
Synchronous processing of the connection check
Short to very short time slice for the connection check
Reliability of the connection check
If possible, not throwing exceptions and not triggering timeouts
I've provided a fresh MongoDB Installation (version 3.6) on the default localhost URL: mongodb://localhost:27017. I've also written down another URL, where there was no MongoDB Database Server: mongodb://localhost:27071.
I'm also using the C# Driver 2.4.4 and do not use the legacy implementation (MongoDB.Driver.Legacy assembly).
So my expectations are, when I'm checking the connection to the first URL, it should give to me the Ok for a alive connection to an existing MongoDB server, when I'm checking the connection to the second URL it should give to me the Fail for a non-existing MongoDB server...
Using the IMongoDatabase.RunCommand method, queries the server and causes the server response timeout to elapse, thus not qualifying against the prerequisites. Furthermore after the timeout, it breaks with a TimeoutException, which requires additional exception handling.
This actual SO question and also this SO question have delivered the most of the start information I needed for my solution... So guys, many thanks for this!
Now my solution:
private static bool ProbeForMongoDbConnection(string connectionString, string dbName)
{
var probeTask =
Task.Run(() =>
{
var isAlive = false;
var client = new MongoDB.Driver.MongoClient(connectionString);
for (var k = 0; k < 6; k++)
{
client.GetDatabase(dbName);
var server = client.Cluster.Description.Servers.FirstOrDefault();
isAlive = (server != null &&
server.HeartbeatException == null &&
server.State == MongoDB.Driver.Core.Servers.ServerState.Connected);
if (isAlive)
{
break;
}
System.Threading.Thread.Sleep(300);
}
return isAlive;
});
probeTask.Wait();
return probeTask.Result;
}
The idea behind this is the MongoDB Server does not react (and seems to be non-existing) until a real attempt is made to access some resource on the server (for example a database). But retrieving some resource alone is not enough, as the server still has no updates to its state in the server's Cluster Description. This update comes first, when the resource is retrieved again. From this time point, the server has valid Cluster Description and valid data inside it...
Generally it seems to me, the MongoDB Server does not proactivelly propagate its Cluster Description to all connected clients. Rather then, each client receives the description, when a request to the server has been made. If some of you fellows have more information on this, please either confirm or deny my understandings on the topic...
Now when we target an invalid MongoDB Server URL, then the Cluster Description remains invalid and we can catch and deliver an usable signal for this case...
So the following statements (for the valid URL)
// The admin database should exist on each MongoDB 3.6 Installation, if not explicitly deleted!
var isAlive = ProbeForMongoDbConnection("mongodb://localhost:27017", "admin");
Console.WriteLine("Connection to mongodb://localhost:27017 was " + (isAlive ? "successful!" : "NOT successful!"));
will print out
Connection to mongodb://localhost:27017 was successful!
and the statements (for the invalid URL)
// The admin database should exist on each MongoDB 3.6 Installation, if not explicitly deleted!
isAlive = ProbeForMongoDbConnection("mongodb://localhost:27071", "admin");
Console.WriteLine("Connection to mongodb://localhost:27071 was " + (isAlive ? "successful!" : "NOT successful!"));
will print out
Connection to mongodb://localhost:27071 was NOT successful!
Here a simple extension method to ping mongodb server
public static class MongoDbExt
{
public static bool Ping(this IMongoDatabase db, int secondToWait = 1)
{
if (secondToWait <= 0)
throw new ArgumentOutOfRangeException("secondToWait", secondToWait, "Must be at least 1 second");
return db.RunCommandAsync((Command<MongoDB.Bson.BsonDocument>)"{ping:1}").Wait(secondToWait * 1000);
}
}
You can use it like so:
var client = new MongoClient("yourConnectionString");
var database = client.GetDatabase("yourDatabase");
if (!database.Ping())
throw new Exception("Could not connect to MongoDb");
This is a solution by using the try-catch approach,
var database = client.GetDatabase("YourDbHere");
bool isMongoConnected;
try
{
await database.RunCommandAsync((Command<BsonDocument>)"{ping:1}");
isMongoConnected = true;
}
catch(Exception)
{
isMongoConnected = false;
}
so when it fails to connect to the database, it will throw an exception and we can handle our bool flag there.
If you want to handle connection issues in your program you can use the ICluster.Description event.
When the MongoClient is created, it will continue to attempt connections in the background until it succeeds.
using MongoDB.Driver;
using MongoDB.Driver.Core.Clusters;
var mongoClient = new MongoClient("localhost")
mongoClient.Cluster.DescriptionChanged += Cluster_DescriptionChanged;
public void Cluster_DescriptionChanged(object sender, ClusterDescriptionChangedEventArgs e)
{
switch (e.NewClusterDescription.State)
{
case ClusterState.Disconnected:
break;
case ClusterState.Connected:
break;
}
}
A button on the aspx page checks whether the connection with the DB2 database server is established or not. My connection String is :
Server=xx.xx.xx.xx:446; Database=dd_unit; UID=db2admin; PWD=Secure*888; CurrentSchema=ptdd;
It is throwing me a SQL30081N error message:
$exception {"ERROR [08001] [IBM] SQL30081N A communication error has been detected. Communication protocol being used: \"TCP/IP\".
Communication API being used: \"SOCKETS\". Location where the error
was detected: \"xx.xx.xx.xx\". Communication function detecting the
error: \"connect\". Protocol specific error code(s): \"10060\",
\"\", \"\". SQLSTATE=08001\r\n"} System.Exception
{IBM.Data.DB2.DB2Exception}
I looked for the SQL30081N error and it is due to connection was terminated by the network by the tcp-ip layer. Now, does the problem is with the Connection String or is it something else? Kindly help me solve this issue.
Code: (Its throwing error after connection is opened)
protected void Button3_Click(object sender, EventArgs e)
{
DB2Connection con = new DB2Connection("Server=xx.xx.xx.xx:446; Database=MyDb; UID=MyUser; PWD=MyPass; CurrentSchema=ptdd;");
try
{
con.Open();
Label1.Visible = true;
Label1.Text = "Conection done";
con.Close();
}
catch (Exception)
{
Label1.Text = "connection failed";
}
P.S. I'm using this to test my application
Port specified was incorrect. It must be 50000 as it is a tcp/ip connection
I am using an SQL connection string with SqlClient.SqlConnection and specifying Connection Timeout=5 in the string, but it still waits 30 seconds before returning failure. How do I make it give up and return faster? I'm on a fast local network and don't want to wait 30 seconds. The servers that are not turned on take 30 seconds to fail. This is just a quick utility program that's going to always run just on this local network.
Edit: Sorry if I was unclear. I want the SqlConnection.Open to fail more quickly. Hopefully that could be deduced from the fact that the servers I want to fail more quickly are turned off.
Edit: It seems that the setting only fails sometimes. Like it knows the IP address of the server, and is using TCP/IP to talk to it (not local) but can't contact SQL Server at that address? I'm not sure what the pattern is, but I don't see the problem when connecting locally with SQL Server stopped, and I don't see it when attempting to connect to a non-existent server. I have seen it when attempting to contact a server where the Windows 2008 firewall is blocking SQL Server, though.
It looks like all the cases that were causing long delays could be resolved much more quickly by attempting a direct socket connection like this:
foreach (string svrName in args)
{
try
{
System.Net.Sockets.TcpClient tcp = new System.Net.Sockets.TcpClient(svrName, 1433);
if (tcp.Connected)
Console.WriteLine("Opened connection to {0}", svrName);
else
Console.WriteLine("{0} not connected", svrName);
tcp.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error connecting to {0}: {1}", svrName, ex.Message);
}
}
I'm going to use this code to check if the server responds on the SQL Server port, and only attempt to open a connection if it does. I thought (based on others' experience) that there would be a 30 second delay even at this level, but I get a message that the machine "actively refused the connection" on these right away.
Edit: And if the machine doesn't exist, it tells me that right away too. No 30-second delays that I can find.
Edit: Machines that were on the network but are not turned off still take 30 seconds to fail I guess. The firewalled machines fail faster, though.
Edit: Here's the updated code. I feel like it's cleaner to close a socket than abort a thread:
static void TestConn(string server)
{
try
{
using (System.Net.Sockets.TcpClient tcpSocket = new System.Net.Sockets.TcpClient())
{
IAsyncResult async = tcpSocket.BeginConnect(server, 1433, ConnectCallback, null);
DateTime startTime = DateTime.Now;
do
{
System.Threading.Thread.Sleep(500);
if (async.IsCompleted) break;
} while (DateTime.Now.Subtract(startTime).TotalSeconds < 5);
if (async.IsCompleted)
{
tcpSocket.EndConnect(async);
Console.WriteLine("Connection succeeded");
}
tcpSocket.Close();
if (!async.IsCompleted)
{
Console.WriteLine("Server did not respond");
return;
}
}
}
catch(System.Net.Sockets.SocketException ex)
{
Console.WriteLine(ex.Message);
}
}
Update 2
I suggest rolling your own timeout. Something like this:
internal static class Program
{
private static void Main(string[] args)
{
Console.WriteLine(SqlServerIsRunning("Server=foobar; Database=tempdb; Integrated Security=true", 5));
Console.WriteLine(SqlServerIsRunning("Server=localhost; Database=tempdb; Integrated Security=true", 5));
}
private static bool SqlServerIsRunning(string baseConnectionString, int timeoutInSeconds)
{
bool result;
using (SqlConnection sqlConnection = new SqlConnection(baseConnectionString + ";Connection Timeout=" + timeoutInSeconds))
{
Thread thread = new Thread(TryOpen);
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
thread.Start(new Tuple<SqlConnection, ManualResetEvent>(sqlConnection, manualResetEvent));
result = manualResetEvent.WaitOne(timeoutInSeconds*1000);
if (!result)
{
thread.Abort();
}
sqlConnection.Close();
}
return result;
}
private static void TryOpen(object input)
{
Tuple<SqlConnection, ManualResetEvent> parameters = (Tuple<SqlConnection, ManualResetEvent>)input;
try
{
parameters.Item1.Open();
parameters.Item1.Close();
parameters.Item2.Set();
}
catch
{
// Eat any exception, we're not interested in it
}
}
}
Update 1
I've just tested this on my own computer using this code:
internal static class Program
{
private static void Main(string[] args)
{
SqlConnection con = new SqlConnection("Server=localhost; Database=tempdb; Integrated Security=true;Connection Timeout=5");
Console.WriteLine("Attempting to open connection with {0} second timeout, starting at {1}.", con.ConnectionTimeout, DateTime.Now.ToLongTimeString());
try
{
con.Open();
Console.WriteLine("Successfully opened connection at {0}.", DateTime.Now.ToLongTimeString());
}
catch (SqlException)
{
Console.WriteLine("SqlException raised at {0}.", DateTime.Now.ToLongTimeString());
}
}
}
and it obeys the Connection Timeout value in the connection string. This was with .NET 4 against SQL Server 2008 R2. Admittedly, it's a localhost connection which may give different results but it means I can't replicate the problem.
I can only suggest trying a similar chunk of code in your network environment and seeing if you continue to see long timeouts.
Old (incorrect) answer
I incorrectly thought the ConnectionTimeout property was settable, but it isn't.
Try setting SqlConnection.ConnectionTimeout instead of using the connection string.
The Command Timeout and the Connection Timeout are two different things.
SqlConnection.ConnectionTimeout is "the time (in seconds) to wait for a connection to open. The default value is 15 seconds." Thats only used when you call SqlConnection.Open().
The SqlCommand.CommandTimeout does what you want to do.