Do I have to lock the database connections when multithreading? - c#

Here is a sample of the class I currently use for database interaction:
using System;
using System.Data;
using System.Collections.Generic;
// Libraries
using log4net;
using log4net.Config;
using MySql.Data.MySqlClient;
namespace AIC
{
class DB
{
private static readonly ILog _logger = LogManager.GetLogger(typeof(DB));
private MySqlConnection _connection;
private MySqlCommand _cmd;
private string _server;
private string _database;
private string _username;
private string _password;
//Constructor
public DB(string server, string database, string username, string password)
{
log4net.Config.XmlConfigurator.Configure();
_server = server;
_database = database;
_username = username;
_password = password;
_connection = new MySqlConnection(string.Format("SERVER={0};DATABASE={1};UID={2};PASSWORD={3};charset=utf8;", _server, _database, _username, _password));
}
public bool TestConnection()
{
try
{
_connection.Open();
_connection.Close();
_logger.Info("Connection test, passed...");
return true;
}
catch (MySqlException ex)
{
_logger.Error(ex.ToString());
return false;
}
}
//open connection to database
private bool Open()
{
try
{
if (_connection.State != ConnectionState.Open)
_connection.Open();
_logger.Info("Starting connection to database...");
return true;
}
catch (MySqlException ex)
{
_logger.Error(ex.ToString());
return false;
}
}
//Close connection
private bool Close()
{
try
{
if (_connection.State != ConnectionState.Closed)
_connection.Close();
_logger.Info("Closing connection to database...");
return true;
}
catch (MySqlException ex)
{
_logger.Error(ex.ToString());
return false;
}
}
// Some basic functions
public bool UserExist(string user)
{
string query = "SELECT user_id FROM users WHERE username=#name LIMIT 1";
if (this.Open())
{
try
{
// Assign the connection
_cmd = new MySqlCommand(query, _connection);
// Prepare to receive params
_cmd.Prepare();
// Fill up the params
_cmd.Parameters.AddWithValue("#name", user);
// returned count bool
bool result = Convert.ToInt32(_cmd.ExecuteScalar()) > 0;
// Close connection
this.Close();
return result;
}
catch (MySqlException ex)
{
_logger.Error(ex.ToString());
this.Close();
return false;
}
}
else
{
_logger.Error("You must be connected to the database before performing this action");
return false;
}
}
public bool AddUser(string user)
{
// .... add user to database
}
public bool DelUser(string user)
{
// .... del user from database
}
public int CountUsers()
{
// .... count total users from database
}
}
}
Currently, I don't have any management for opening and closing the connections so it will always check wether the database is connected or not, perform the action and close it as shown in the UserExist function.
Considering this, it came to my attention that I might be closing my own connections in the middle or their transactions since I am using this in 2 different threads.
My doubt here is wether this simple class could lock my application for any reason making it unresponsive or cause me any troubles in the long run?
What should I consider, improve, etc.?
Would appreciate code samples.

Each thread should have its own connection instance, in your case probably an instance of Db.
But the problem would be solved (a lot) better by not storing a connection in your Db objects at all. The best pattern is to only use connections as local variables in a using() {} statement.
Currently, your class should implement IDisposable (just for the case where your try/catch logic fails).

Waiting for exceptions to be thrown and then handle them is not a good way for design a multithreading class. a good design will be with using lock statement. when using a lock you are providing a critical regions so only one thread is allowed to access to the resources at time. once one thread finish its usage the other can proceed and so on.
For example:
so it will always check wether the database is connected or not, perform the action and close
what will happen if two threads try to enter to the same method concurrently? one thread checking if the connection is not set to continue and it finds that the connection is not set so it proceed. but at the middle of its process and before it connects, the Thread Context Switching switches to the other thread and pause the first one, the second thread in turn ask if the connection was set and it will find that it is not, so it connect and proceed. Now the thread context switching switches to the first thread to continue its execution. and the problems begins...
But the scenario is different when using 'lock'; One and only one thread will allowed to access to the method region that marked with the lock. So one thread enter the lock region and establish the connection. at that time the other thread try to access to the method but the first one is still there so the second will be waiting until the first one finishes its work and then it will proceed.

You don't have to lock them, but yes: you must ensure 2 threads aren't using the same connection at the same time.
Synchronisation (locks, etc) is one way to do that; isolation is another (better, IMO) way. If two threads never have the same connection then all is good. For this reason, a static connection is never a good idea.

Related

Managing and Closing Dynamically created SQL connections in .net

I have a c# windows form application that connects to databases dynamically where each user may connect to different databases.
The current implementation is as follows:
Connection Repository that contains a dynamically populated list of connections (per user).
When a user initiates a request that requires a database connection the respective connection is looked up from the connection repository ,opened , and then used in the user request .
Code Sample from the connection repository
public class RepoItem
{
public string databasename;
public SqlConnection sqlcnn;
}
public class ConnectionRepository
{
private List<RepoItem> connectionrepositroylist;
public SqlConnection getConnection(String dbname)
{
SqlConnection cnn = (from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).Single;
cnn.Open();
return cnn;
}
}
sorry for any code errors i just improvised a small version of the implementation for demonstration purpose.
I'am not closing connections after a command execution because it may be used by another command simultaneously.
The questions are:
Should i be worried about closing the connections ?
Does connection close automatically if it is idle for a specific period ?
I have a method in mind to implement a timer in the created Connection Repository and check for idle connections through the Executing ConnectionState Enumeration and close them manually.
Any suggestions are welcome .
When i want a specific connection i call the getConnection function in the ConnectionRepository class and pass the database name as a parameter.
PS: I didn't post the complete implemented code because it is quite big and includes the preferences that affect the populating of the connection list.
I would suggest not to return the SQLConnection to the calling method at all.
Instead, create a method that will accept an Action<SqlConnection>, create the connection inside a using block, and execute the action inside that block
This way you know that the connection will always be correctly closed and disposed, while giving the using code the freedom to do whatever it needs:
public class RepoItem
{
public string databasename;
public SqlConnection sqlcnn;
}
public class DatabaseConnector
{
private List<RepoItem> connectionrepositroylist;
private SqlConnection GetConnection(String dbname)
{
return (from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).SingleOrDefault();
}
public void Execute(String dbname, Action<SqlConnection> action)
{
using (var cnn = GetConnection(dbname))
{
if (cnn != null) // in case dbname is not in the list...
{
cnn.Open();
action(cnn);
}
}
}
}
Then, to execute an sql statement you can do something like this:
public void ExecuteReaderExample(string dbName, string sql)
{
Execute("dbName",
connection =>
{
using (var cmd = new SqlCommand(sql, connection))
{
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// do stuff with data form the database
}
}
}
});
}
Of course, you can also wrap the SqlCommand in a method like this.
I've been working with this approach for quite some time now, and as far as I can tell it's working well. In fact, It's working so well I've published a project on git hub based on this approach.
It saves you a lot of the plumbing when dealing with ado.net, by wrapping the connection, command, reader and adapter much the same way.
Feel free to download it and adapt to your needs.
P.S.
To answer your questions directly:
Should i be worried about closing the connections ?
Yes, you should.
Does connection close automatically if it is idle for a specific period ?
No, it doesn't.
However, implementing a method like I suggested will handle closing and disposing the connection object for you, so you don't need to worry about it.
Update
As Yahfoufi wrote in his comment, this design has a flaw, since multiple commands are using the same instance of SqlConnection, you are risking closing the connection while other commands are running.
However, fixing this design flaw is very easy - instead of holding SqlConnection in RepoItem you can simply hold the connection string:
public class RepoItem
{
public string DatabaseName {get; set;}
public string ConnectionString {get; set;}
}
Then you change the GetConnection method like this:
private SqlConnection GetConnection(String dbname)
{
return new SqlConnection(from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).SingleOrDefault());
}
Now each Execute method is working on it's own individual instance of SqlConnection so you don't need to worry about closing in the middle of some other command executing.
However, While we are on the subject of refactoring, I would suggest removing the RepoItem class all together and instead of using a List<RepoItem> to hold the connection strings simply use a Dictionary<string, string>, where the database name is the key and the connection string is the value. This way you can only have one connection string per database name, and your GetConnection method is simplified to this:
private Dictionary<string, string> connectionrepositroylist;
private string GetConnectionString(String dbname)
{
return connectionrepositroylist.ContainsKey(dbname) ? connectionrepositroylist[dbname] : "";
}
So, the complete DatabaseConnector class will look like this:
public class DatabaseConnector
{
private Dictionary<string, string> connectionrepositroylist;
private string GetConnectionString(String dbname)
{
return connectionrepositroylist.ContainsKey(dbname) ? connectionrepositroylist[dbname] : "";
}
public void Execute(String dbname, Action<SqlConnection> action)
{
var connectionString = GetConnectionString(dbname);
if(!string.IsNullOrEmpty(connectionString))
{
using (var cnn = new SqlConnection(connectionString))
{
cnn.Open();
action(cnn);
}
}
}
// Of course, You will need a way to populate your dictionary -
// I suggest having a couple of methods like this to add, update and remove items.
public bool AddOrUpdateDataBaseName(string dbname, string connectionString)
{
if(connectionrepositroylist.ContainsKey(dbname))
{
connectionrepositroylist[dbname] = connectionString;
}
else
{
connectionrepositroylist.Add(dbname, connectionString);
}
}
}
The good news is that ADO.Net manages your connection pools dynamically, so there's minimal overhead in you dynamically opening and closing connections in code. There's a good document here if you want to look through the detail.
To answer the specific questions you've raised:
Should i be worried about closing the connections ?
Yes, but not for the reasons you may think. Microsoft encourage you to close your connections, so as to return them to the pool for (re)use elsewhere in your code. Closing the connection doesn't actually close it - it merely returns the underlying connection to the pool. Failure to close your connections properly can lead to delays in them being returned to the pool, thus adversely affecting your applications performance as more connections need to be added to the pool to cope with demand.
Does connection close automatically if it is idle for a specific
period ?
A connection is only returned to the pool when it's Dispose or Finalise methods get called. If you create a connection and drop it into a static container then it will not be returned to the pool at all. As such, your ConnectionRepository may actually be harming performance.
I have a method in mind to implement a timer in the created Connection
Repository and check for idle connections
This is unnecessary - close your connections to allow them to return to the pool. This way they will be available for other threads to use
Personally, I'd suggest that you modify your RepoItem class to store connection strings, rather than connection objects, and let ADO.Net's pooling do all the heavy lifting.
public static class ConnectionRepository
{
private static readonly Dictionary<string, string> Connections = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
public static bool Contains(string key)
{
return Connections.ContainsKey(key);
}
public static void Add(string key, string connectionString)
{
Connections.Add(key, connectionString);
}
public static SqlConnection Get(string key)
{
var con = new SqlConnection(Connections[key]);
con.Open();
return con;
}
}
With this in place, you can query the database as follows:
public static void foo()
{
using (var con = ConnectionRepository.Get("MyConnection"))
using (var cmd = new SqlCommand("SELECT * FROM MyTable", con))
{
var dr = cmd.ExecuteReader();
//...
}
}
Once the query has executed and the connection is no longer required, the using() block calls its Dispose() method and releases the underlying connection back to the pool for re-use.
As #tinudu says, the SqlConnection class reuses existing connections automatically - you don't have to implement that yourself. See SQL Server Connection Pooling.
If you create the SqlConnection object in a using statement, C# will close the connection automatically as required.
Wrapping the whole thing (create connection, open, run query, close connection) in a function is the best idea. You can put the function in a repository base-class, so it is available to all your repositories.
You would need several functions for the different types of SQL query (select, update, stored proc) but you only need to write one of each - they will get reused.
if you worried about so many conditions let say parallel execution as
well so consider reserving connections for app and close all at once
when app is closing.
public class RepoItem
{
public string databasename;
public SqlConnection sqlcnn;
}
public class ConnectionRepository
{
private List<RepoItem> connectionrepositroylist;
public SqlConnection getConnection(String dbname)
{
SqlConnection cnn = (from n in connectionrepositroylist
where n.databasename == dbname
select n.sqlcnn).Single;
if (cnn!= null && cnn.State == cnn.Closed) // Impelement other checks as well
{
cnn.Open();
}
return cnn;
}
}
Implement CloseConnections and call while application closing i.e
Application.ApplicationExit event
public void CloseConnections()
{
foreach (var connection in connectionrepositroylist)
{
try
{
if (connection.State == System.Data.ConnectionState.Open) // check other conditions
{
connection.Close();
}
}
catch (Exception)
{
//logging or special handling
}
}
}
Points to be note
If some query is still executing and user tries to shut down or close the
app can consider following implementations
Wont allow the application shutdown . Callback delegate will help in this
case to ensure that query is returned.
Force stop and close the connection
It is a better Practice to close the sqlconnection manually, Since it can release the connection which can be used for other processes. Also note that you should open the connection as much as late you can and close it early as possible.

Thread.Abort doesn't release a file

I made a code that create a Database in .sqlite, all working good but I want to be sure that when the user start for the first time the application the Database population must be completed. If the user abort the database population, the database must be deleted (because the application don't working with an incomplete resource). Now I've used the thread for execute the method that create this Database, and I've declared the thread variable global in the class, like:
Thread t = new Thread(() => Database.createDB());
The Database.createDB() method create the DB. All working perfect, the DB is created correctly. Now I fire the closing of the window that creating the DB like:
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
MessageBoxResult result = MessageBox.Show(
#"Sure?",
"Attention", MessageBoxButton.YesNo, MessageBoxImage.Question);
try
{
if (result == MessageBoxResult.Yes)
{
t.Abort();
if (File.Exists("Database.sqlite"))
{
File.Delete("SoccerForecast.sqlite");
Process.GetCurrentProcess().Kill();
} ....
The event was fired correct and the thread stopped, but when the condition start if (File.Exists("Database.sqlite")) the compiler tell me:
Can't delete file - in using by another process.
But I've stopped the thread, why this exception appear? What I doing wrong?
UPDATE:
In CreateDb() method I also have a call to other method of different class, one of this have the structure like this:
public void setSoccer()
{
Database.m_dbConnection.Open();
string requestUrl = "...";
string responseText = Parser.Request(requestUrl);
List<SoccerSeason.RootObject> obj = JsonConvert.DeserializeObject<List<SoccerSeason.RootObject>>(responseText);
foreach (var championships in obj)
{
string sql = "string content";
SQLiteCommand command = new SQLiteCommand(sql, Database.m_dbConnection);
try
{
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
string query = "select * from SoccerSeason";
SQLiteCommand input = new SQLiteCommand(query, Database.m_dbConnection);
SQLiteDataReader reader = input.ExecuteReader();
int i = 0;
while (reader.Read())
{
//reading data previously inserted in the database
}
Database.m_dbConnection.Close(); /
}
I was wondering where I should put the flag variable because this code have a different loop inside.
It could be that when you're aborting the thread it's not cleanly closing the database connections, hence the error you're seeing.
Might I suggest a slight redesign because using Thread.Abort is not ideal.
Instead use a variable as a cancel flag to notify the thread to shut down.
Then when the thread detects that this cancel flag is set it can properly close connections and handle the database delete itself.
Update:
A brief example to illustrate what I mean; it ain't pretty and it won't compile but it gives the general idea.
public class Database
{
public volatile bool Stop= false;
public void CreateDb()
{
if(!Stop)
{
// Create database
}
if(!Stop)
{
// Open database
// Do stuff with database
}
// blah blah ...
if(Stop)
{
// Close your connections
// Delete your database
}
}
}
...
protected override void OnClosing(CancelEventArgs e)
{
Database.Stop = true;
}
And now that you know roughly what you're looking for I heartily recommend Googling for posts on thread cancellation by people who know what they're talking about that can tell you how to do it right.
These might be reasonable starting points:
How to: Create and Terminate Threads
.NET 4.0+ actually has a CancellationToken object with this very purpose in mind Cancellation in Managed Threads

How to lock a object when using load balancing

Background: I'm writing a function putting long lasting operations in a queue, using C#,
and each operation is kind of divided into 3 steps:
1. database operation (update/delete/add data)
2. long time calculation using web service
3. database operation (save the calculation result of step 2) on the same db table in step 1, and check the consistency of the db table, e.g., the items are the same in step 1 (Pls see below for a more detailed example)
In order to avoid dirty data or corruptions, I use a lock object (a static singleton object) to ensure the 3 steps to be done as a whole transaction. Because when multiple users are calling the function to do operations, they may modify the same db table at different steps during their own operations without this lock, e.g., user2 is deleting item A in his step1, while user1 is checking if A still exists in his step 3. (additional info: Meanwhile I'm using TransactionScope from Entity framework to ensure each database operation as a transaction, but as repeat readable.)
However, I need to put this to a cloud computing platform which uses load balancing mechanism, so actually my lock object won't take effect, because the function will be deployed on different servers.
Question: what can I do to make my lock object working under above circumstance?
This is a tricky problem - you need a distributed lock, or some sort of shared state.
Since you already have the database, you could change your implementation from a "static C# lock" and instead the database to manage your lock for you over the whole "transaction".
You don't say what database you are using, but if it's SQL Server, then you can use an application lock to achieve this. This lets you explicitly "lock" an object, and all other clients will wait until that object is unlocked. Check out:
http://technet.microsoft.com/en-us/library/ms189823.aspx
I've coded up an example implementation below. Start two instances to test it out.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var locker = new SqlApplicationLock("MyAceApplication",
"Server=xxx;Database=scratch;User Id=xx;Password=xxx;");
Console.WriteLine("Aquiring the lock");
using (locker.TakeLock(TimeSpan.FromMinutes(2)))
{
Console.WriteLine("Lock Aquired, doing work which no one else can do. Press any key to release the lock.");
Console.ReadKey();
}
Console.WriteLine("Lock Released");
}
class SqlApplicationLock : IDisposable
{
private readonly String _uniqueId;
private readonly SqlConnection _sqlConnection;
private Boolean _isLockTaken = false;
public SqlApplicationLock(
String uniqueId,
String connectionString)
{
_uniqueId = uniqueId;
_sqlConnection = new SqlConnection(connectionString);
_sqlConnection.Open();
}
public IDisposable TakeLock(TimeSpan takeLockTimeout)
{
using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Suppress))
{
SqlCommand sqlCommand = new SqlCommand("sp_getapplock", _sqlConnection);
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.CommandTimeout = (int)takeLockTimeout.TotalSeconds;
sqlCommand.Parameters.AddWithValue("Resource", _uniqueId);
sqlCommand.Parameters.AddWithValue("LockOwner", "Session");
sqlCommand.Parameters.AddWithValue("LockMode", "Exclusive");
sqlCommand.Parameters.AddWithValue("LockTimeout", (Int32)takeLockTimeout.TotalMilliseconds);
SqlParameter returnValue = sqlCommand.Parameters.Add("ReturnValue", SqlDbType.Int);
returnValue.Direction = ParameterDirection.ReturnValue;
sqlCommand.ExecuteNonQuery();
if ((int)returnValue.Value < 0)
{
throw new Exception(String.Format("sp_getapplock failed with errorCode '{0}'",
returnValue.Value));
}
_isLockTaken = true;
transactionScope.Complete();
}
return this;
}
public void ReleaseLock()
{
using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Suppress))
{
SqlCommand sqlCommand = new SqlCommand("sp_releaseapplock", _sqlConnection);
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("Resource", _uniqueId);
sqlCommand.Parameters.AddWithValue("LockOwner", "Session");
sqlCommand.ExecuteNonQuery();
_isLockTaken = false;
transactionScope.Complete();
}
}
public void Dispose()
{
if (_isLockTaken)
{
ReleaseLock();
}
_sqlConnection.Close();
}
}
}
}

Recommended practice for stopping transactions escalating to distributed when using transactionscope

Using the TransactionScope object to set up an implicit transaction that doesn't need to be passed across function calls is great! However, if a connection is opened whilst another is already open, the transaction coordinator silently escalates the transaction to be distributed (needing MSDTC service to be running and taking up much more resources and time).
So, this is fine:
using (var ts = new TransactionScope())
{
using (var c = DatabaseManager.GetOpenConnection())
{
// Do Work
}
using (var c = DatabaseManager.GetOpenConnection())
{
// Do more work in same transaction using different connection
}
ts.Complete();
}
But this escalates the transaction:
using (var ts = new TransactionScope())
{
using (var c = DatabaseManager.GetOpenConnection())
{
// Do Work
using (var nestedConnection = DatabaseManager.GetOpenConnection())
{
// Do more work in same transaction using different nested connection - escalated transaction to distributed
}
}
ts.Complete();
}
Is there a recommended practise to avoid escalating transactions in this way, whilst still using nested connections?
The best I can come up with at the moment is having a ThreadStatic connection and reusing that if Transaction.Current is set, like so:
public static class DatabaseManager
{
private const string _connectionString = "data source=.\\sql2008; initial catalog=test; integrated security=true";
[ThreadStatic]
private static SqlConnection _transactionConnection;
[ThreadStatic] private static int _connectionNesting;
private static SqlConnection GetTransactionConnection()
{
if (_transactionConnection == null)
{
Transaction.Current.TransactionCompleted += ((s, e) =>
{
_connectionNesting = 0;
if (_transactionConnection != null)
{
_transactionConnection.Dispose();
_transactionConnection = null;
}
});
_transactionConnection = new SqlConnection(_connectionString);
_transactionConnection.Disposed += ((s, e) =>
{
if (Transaction.Current != null)
{
_connectionNesting--;
if (_connectionNesting > 0)
{
// Since connection is nested and same as parent, need to keep it open as parent is not expecting it to be closed!
_transactionConnection.ConnectionString = _connectionString;
_transactionConnection.Open();
}
else
{
// Can forget transaction connection and spin up a new one next time one's asked for inside this transaction
_transactionConnection = null;
}
}
});
}
return _transactionConnection;
}
public static SqlConnection GetOpenConnection()
{
SqlConnection connection;
if (Transaction.Current != null)
{
connection = GetTransactionConnection();
_connectionNesting++;
}
else
{
connection = new SqlConnection(_connectionString);
}
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
return connection;
}
}
Edit: So, if the answer is to reuse the same connection when it's nested inside a transactionscope, as the code above does, I wonder about the implications of disposing of this connection mid-transaction.
So far as I can see (using Reflector to examine code), the connection's settings (connection string etc.) are reset and the connection is closed. So (in theory), re-setting the connection string and opening the connection on subsequent calls should "reuse" the connection and prevent escalation (and my initial testing agrees with this).
It does seem a little hacky though... and I'm sure there must be a best-practise somewhere that states that one should not continue to use an object after it's been disposed of!
However, since I cannot subclass the sealed SqlConnection, and want to maintain my transaction-agnostic connection-pool-friendly methods, I struggle (but would be delighted) to see a better way.
Also, realised that I could force non-nested connections by throwing exception if application code attempts to open nested connection (which in most cases is unnecessary, in our codebase)
public static class DatabaseManager
{
private const string _connectionString = "data source=.\\sql2008; initial catalog=test; integrated security=true; enlist=true;Application Name='jimmy'";
[ThreadStatic]
private static bool _transactionHooked;
[ThreadStatic]
private static bool _openConnection;
public static SqlConnection GetOpenConnection()
{
var connection = new SqlConnection(_connectionString);
if (Transaction.Current != null)
{
if (_openConnection)
{
throw new ApplicationException("Nested connections in transaction not allowed");
}
_openConnection = true;
connection.Disposed += ((s, e) => _openConnection = false);
if (!_transactionHooked)
{
Transaction.Current.TransactionCompleted += ((s, e) =>
{
_openConnection = false;
_transactionHooked = false;
});
_transactionHooked = true;
}
}
connection.Open();
return connection;
}
}
Would still value a less hacky solution :)
One of the primary reasons for transaction escalation is when you have multiple (different) connections involved in a transaction. This almost always escalates to a distributed transaction. And it is indeed a pain.
This is why we make sure that all our transactions use a single connection object. There are several ways to do this. For the most part, we use the thread static object to store a connection object, and our classes that do the database persistance work, use the thread static connection object (which is shared of course). This prevents multiple connections objects from being used and has eliminated transaction escalation. You could also achieve this by simply passing a connection object from method to method, but this isn't as clean, IMO.

Test sql connection without throwing exception

To test if i can connect to my database, I execute the following code :
using (SqlConnection connection = new SqlConnection(myConnectionString))
{
try
{
connection.Open();
canConnect = true;
}
catch (SqlException) { }
}
This works except it throws an exception if the connection failed. Is there any other way to test a Sql connection that doesn't throw an exception ?
Edit :
To add precision, i'm asking if there is a simple method that does that without having to open the connection and catch exceptions that can occur
When attempting to open a connection, there is no way to avoid the exception if the connection can't be opened. It can be hidden away in a function somewhere, but you're going to get the exception, no matter what.
It was designed like this because generally you expect to be able to connect to the database. A failed connection is the exception.
That being said, you can test the current connection state at any time by checking the State property.
write an extension like so:
public static class Extension{
public static bool CanOpen(this SqlConnection connection){
try{
if(connection == null){ return false; }
connection.Open();
var canOpen = connection.State == ConnectionState.Open;
connection.close();
return canOpen;
}
catch{
return false;
}
}
Then you can consume it like:
using(var connection = new SqlConnection(myConnectionString)){
if(connection.CanOpen()){
// NOTE: The connection is not open at this point...
// You can either open it here or not close it in the extension method...
// I prefer opening the connection explicitly here...
}
}
HTH.
If it throws an an exception and you handle it in your catch block you already know the connection failed. I think you answered your own question.
I think the real answer here is ping.
string data = "ismyserverpingable";
byte[] buffer = Encoding.ASCII.GetBytes (data);
int timeout = 120;
PingReply reply = pingSender.Send ("google.com", timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
}
Unless you are explicitly checking to see if a sql connection is possible 9/10 you should know if something is a sql server. This would save you that nasty memory usage of an exception which is what i am betting you are really after.
You can not avoid exception coming while connecting database but have some function which handle this very well. I am using this function which return true if connection exist.
public static bool IsSQLConnectionAvailable()
{
SqlConnection _objConn = new SqlConnection();
try
{
_objConn.ConnectionString = ConfigurationManager.ConnectionStrings["DefaultSQLConnectionString"].ConnectionString;
_objConn.Open();
}
catch
{
return false;
}
finally
{
if (_objConn.State == ConnectionState.Open)
_objConn.Close();
}
return true;
}
You could always use the ConnectionStringBuilder class and check for the existence of each piece that is required by a connection string before attempting to open it.
If the connection string is correct, but the database server you're connecting to is down, you're still going to get an excepton. Kind of pointless to check the quality of the string if the endpoint you're connecting to can potentially be offline.
I'd like to share the whole solution I've implemented to avoid checking the connection at every call. If the connection string is wrong an exception stops the execution, otherwise the attempt to open the connectionstring is done just once for each connectionstring.
Since the connection is often multithreaded I've added a syncobj used by the lock which checks
#if DEBUG
private static object syncobj = new object();
private static ConcurrentDictionary<string, bool> CheckedConnection = new ConcurrentDictionary<string, bool>();
private static void CheckCanOpenConnection(SqlConnection connection)
{
lock (syncobj)
{
try
{
CheckedConnection.TryGetValue(connection.ConnectionString, out bool found);
if (found)
{
return;
}
else
{
connection.Open();
var canOpen = connection.State == ConnectionState.Open;
connection.Close();
CheckedConnection.TryAdd(connection.ConnectionString, true);
return;
}
}
catch
{
throw new ApplicationException("Unable to connect to: " + connection.ConnectionString);
}
}
}
#endif
Here is the call to from the method which instantiate the connection
private SqlConnection CreateConnection()
{
if (_connection == null)
{
_connection = new SqlConnection(this.ConnectionString);
#if DEBUG
CheckCanOpenConnection(_connection);
#endif
}
return _connection;
}

Categories

Resources