how to manage multiple ado.net database connections from asmx Web Service - c#

Since IIS assigns a worker thread for each request I've intention to create new object to serve each request. I have 2 questions:
Is it efficient to create new object to serve each request? (is there even alternatice?)
Is it thread safe, efficient and best practice to create new connection, and open&close it for each request like below:
using (MySqlConnection conn = new MySqlConnection(ConfigurationManager.ConnectionStrings["MySqlConnectionString"].ConnectionString))
{
conn.Open();
MySqlCommand cmd = new MySqlCommand("SELECT password FROM Admin WHERE username='" + username + "'", conn);
object dbp = cmd.ExecuteScalar();
conn.Close();
}
PS. this example is taken from this site. I use oracle db.
Thanks: Matti

When you do new SomeSqlConnection() you actually don't create a new connection every time. As database connections are expensive to create ADO.NET keeps a connection pool and draws connections from there. You could also remove the call to the Close method. Here's a snippet you can safely use in each request:
var connectionString = ConfigurationManager.ConnectionStrings["MySqlConnectionString"].ConnectionString;
using (var conn = new MySqlConnection(connectionString))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT count(*) from some_table";
object result = cmd.ExecuteScalar();
}

As Darin correctly states in his answer, you should allow the connection pooling mechanism to do its job. Don't try and build something 'clever', it won't be as good.
The golden rule with expensive resources such as database connections is to acquire late and release early. As long as you abide by that then you'll do just fine.

Related

Calling a linked server fails after a snapshot connection has been disposed

We have a C# application using ADO.NET and an SQL-Server with SNAPSHOT Transaction Isolation Level. This is 'as is' and unfortunately cannot be modified.
Now we need insert stuff on a linked server.
We execute the following code (reduced to illustrate the problem):
// Create a snapshot Transaction and close the connection
using (var con = new SqlConnection(myConStr))
{
con.BeginTransaction(TransactionLevel.Snapshot);
}
// do something with a linked server
using (var con = new SqlConnection(myConStr))
{
using (var cmd = con.CreateCommand()
{
cmd.CommandText = "insert into LinkedServer.SomeDb..Table ...";
cmd.ExecuteNonQuery();
}
}
We get can an exception when trying to insert something into the linked server
'Remote access is not supported for transaction isolation level "SNAPSHOT"'
I wonder why it is not possible: We open the connection, make sure it is disposed (clearing all transactions, I guess) and use a second connection for the linked server call.
Executing the stuff in SSMS using plain SQL seems to work.
What are we missing? Is there a proper way to do it?
Thanks for any hints in the right direction.
The secret to understand the problem is the 'connection pooling' which is done by ADO.NET in the Background. The real connection is actually set to SNAPSHOT.
In the second part of the sample code, that connection simply gets reused thus still being in 'snapshot mode'.
The solution is to explicitly set the transaction isolation Level to something else right after opening the Connection.
using (var con = new SqlConnection(myConStr))
{
using (var cmd = con.CreateCommand()
{
cmd.CommandText = "set transaction isolation Level read committed";
cmd.ExecuteNonQuery();
}
using (var cmd = con.CreateCommand()
{
cmd.CommandText = "insert into LinkedServer.SomeDb..Table ...";
cmd.ExecuteNonQuery();
}
}

C# How to open a SQL Anywhere connection alongside an Entity Framework connection

I have a C#, .Net 4.5.2 project, built in VS2012, which uses Entity Framework to connect to a SQL database. I now need to access a separate Oracle database, and have been trying to use SQL Anywhere 16 to make the connection. I know that the SQL Anywhere connection works because I have a test project which successfully uses it. The problem is that the connection.Open() method errors with this message:
Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool.
I suspect that Entity Framework doesn't like the additional connection, but enabling MSDTC is not an option as I only have FTP access to the server where the code will live. Is anyone able to suggest an alternative way to get this working, bearing in mind I know very little about Entity Framework?
Additional
There aren't any transactions set up as far as I can see (I only wrote the stuff for connecting to the Oracle database), nor is TransactionScope being used. Here's an edited version of my code:
var connectionString = new SAConnectionStringBuilder();
connectionString.Host = "***.***.***.***";
connectionString.DatabaseName = "*****";
connectionString.UserID = "*****";
connectionString.Password = "*****";
connectionString.ServerName = "*****";
using (SAConnection conn = new SAConnection(connectionString))
{
using (SACommand cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.CommandType = CommandType.Text;
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}
Solution
I did some more searching, and after a bit of trial and error, managed to solve my problem. It seems the SQL Anywhere connection was automatically being put into a transaction. When this was then combined with the transactions being used by the entity framework connection, it was raised to a distributed transaction.
I have found that by putting the connection inside a transaction scope, and using the TransactionScopeOption.Suppress flag, it is no longer being put into a transaction, and therefore does not require MSDTC to be enabled. My code now looks like this:
var connectionString = new SAConnectionStringBuilder();
connectionString.Host = "***.***.***.***";
connectionString.DatabaseName = "*****";
connectionString.UserID = "*****";
connectionString.Password = "*****";
connectionString.ServerName = "*****";
using (TransactionScope scope1 = new TransactionScope(TransactionScope.Suppress))
{
using (SAConnection conn = new SAConnection(connectionString))
{
using (SACommand cmd = conn.CreateCommand())
{
cmd.CommandText = query;
cmd.CommandType = CommandType.Text;
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}
scope1.Complete();
}
Thanks to everyone who responded

How to close a forgotten connection?

I created a connection and an SqlReader but forgot to close both of them:
SqlConnection conn = new SqlConnection("connection info");
conn.Open();
string sql = "SQL command HERE";
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader reader = cmd.ExecuteReader();
Now when try to run the code again it always gives me this error:
System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
This link told me how to properly open and close a connection but didn't explain anything on how to close one still running.
I tried shuting down the pc, I tried looking into the database's options on SQL server (found none useful)... I changed the code to do just the close of both the connection and the reader (it compiled and runned but the problem remained after changing back the code).
How can I close this "ghost" connection? Is there any way (brute force) to close all running connections?
[EDIT:] I couldn't really solve the problem. The workaround was to add MultipleActiveResultSets=true to the connection string
I don't think you can access the ghost object, for future, just use using construct where it's possible:
using(SqlConnection conn = new SqlConnection("connection info"))
{
conn.Open();
string sql = "SQL command HERE";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader reader = cmd.ExecuteReader();
....
}
Wrap the creation in a using statement - this will always ensure the connection gets closed:
using(SqlConnection conn = new SqlConnection("connection info"))
{
// your code
}
Looking at all the answers, they seem to tell you how to avoid the problem.
If I'm not mistaken, what you mean is that a connection exists on both the client (your PC) and the server (The sql server) because you forgot to close it, and you're worried about it hanging out there forever.
Think of your connection to the server as a phone conversation. I could hang up on you, but it takes a few seconds for your phone to realize the connection is lost. You may sit there wondering if I've hung up, or just stopped talking. You really don't know. This is what happens on the server when a connection isn't closed properly. (On older landlines, you could leave the phone off the hook and tied up the line indefinitely.)
By closing the connection in code, you are effectively telling the server to close their end of the connection before closing your own. if you FAIL to close the conneciton, it will be closed on your end when the program exits or if you reboot, but the server may sit there with an open connection. (Think of someone sitting there wondering "Did he just hang up on me?")
If I'm not mistaken, what you want to get to is closing it at the SQL server end. (Getting them to "hang up".)
After rebooting, it is absolutely closed on your end. It should clear on its own at the server.
However, if you want to do it yourself, you can clear it at the server in code end using this info: How do you kill all current connections to a SQL Server 2005 database?
A far easier approach would be to just do it in SQL Server Management Studio as described here: http://www.mikebevers.be/blog/2009/07/kill-open-sql-processes-connections/
All of these answers tell you how to avoid the problem, but they don't explain what the problem is.
A SqlDataReader provides forward-only data access, which means that once you have used it and are done, you must close create a new one. See this blog for a detailed explanation. Basically, if you don't close the DataReader, then underthehood it will remain open dedicated to that connection and command.
As others have stated, its best to ensure you close all your resources.
using (SqlConnection connection = new SqlConnection("...")) {
connection.Open();
string sql = "SQL command HERE";
using (SqlCommand cmd = new SqlCommand(sql, con))
using (SqlDataReader reader = cmd.ExecuteReader()) {
// do your stuff
}
}
Truth be told even when you "close" or "dispose" of a connection it does not really go away unless you explicitly disable Pooling in your connection string. You can however do this
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.clearpool.aspx
I know this is an old post, and this may help no one. But I saw a opportunity to post what I saw wrong with this question.
First, you are creating a SqlConnection named conn but in your SqlCommand named cmd you are calling con as your connection. This is a problem:
SqlConnection conn = new SqlConnection("connection info");
conn.Open();
string sql = "SQL command HERE";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader reader = cmd.ExecuteReader();
This might be why it's giving you the error:
System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
Second, to close a conn after you are done you use:
conn.Close();
Third, to close a SqlDataReader you use:
reader.Close();
But you just assigned the SqlDataReader to reader. You never actually opened the SqlDataReader. To open it use:
reader.Read();
Or:
while (reader.Read())
{
// Code
}
Now a proper way to initilaize a connection and a SqlDataReader while opening and close them:
using (SqlConnection conn = new SqlConnection(sqlConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = "SELECT * FROM TableName;";
SqlDataReader reader = cmd.ExecuteReader();
reader.Read();
if (reader.HasRows)
{
strCol1 = reader.GetValue(0).ToString();
}
reader.Close();
}
conn.Close();
}

Application Role in Program connecting the SQL Server

I have a program which would use the Application Role to write data to a SQL Server 2005.
using (SqlConnection sqlCon = new SqlConnection(connectionString))
{
SqlCommand sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlCon;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.CommandText =
"EXEC sp_setapprole 'application Role name','password';";
sqlCommand.CommandText += sqlComm;
sqlCommand.CommandTimeout = 300;
sqlCon.Open();
int res = sqlCommand.ExecuteNonQuery();
}
This code is in a loop. for the first time, it's OK. In second iterator, it throws exception.
The connection has been dropped because the principal that opened it subsequently assumed a new security context, and then tried to reset the connection under its impersonated security context. This scenario is not supported. See "Impersonation Overview" in Books Online.
Event ID 18059
Source MSSQLSERVER
Is there anyone meet this problem before?
Best Regards,
turn off connection pooling, explicitly. by default is on and connection pooling does not work with unreversible impersonation like approles.
The using{} statement calls IDispose at the end of the block thus killing your connection.
https://msdn.microsoft.com/en-us/library/yh598w02.aspx
using Statement (C# Reference)

Managing SQL Server Connections

What is the the best practice for SQL connections?
Currently I am using the following:
using (SqlConnection sqlConn = new SqlConnection(CONNECTIONSTRING))
{
sqlConn.Open();
// DB CODE GOES HERE
}
I have read that this is a very effective way of doing SQL connections. By default the SQL pooling is active, so how I understand it is that when the using code ends the SqlConnection object is closed and disposed but the actual connection to the DB is put in the SQL connection pool. Am i wrong about this?
That's most of it. Some additional points to consider:
Where do you get your connection string? You don't want that hard-coded all over the place and you may need to secure it.
You often have other objects to create as well before your really use the connection (SqlCommand, SqlParameter, DataSet, SqlDataAdapter), and you want to wait as long as possible to open the connection. The full pattern needs to account for that.
You want to make sure your database access is forced into it's own data layer class or assembly. So a common thing to do is express this as a private function call:
.
private static string connectionString = "load from encrypted config file";
private SqlConnection getConnection()
{
return new SqlConnection(connectionString);
}
And then write your sample like this:
using (SqlConnection sqlConn = getConnection())
{
// create command and add parameters
// open the connection
sqlConn.Open();
// run the command
}
That sample can only exist in your data access class. An alternative is to mark it internal and spread the data layer over an entire assembly. The main thing is that a clean separation of your database code is strictly enforced.
A real implementation might look like this:
public IEnumerable<IDataRecord> GetSomeData(string filter)
{
string sql = "SELECT * FROM [SomeTable] WHERE [SomeColumn] LIKE #Filter + '%'";
using (SqlConnection cn = getConnection())
using (SqlCommand cmd = new SqlCommand(sql, cn))
{
cmd.Parameters.Add("#Filter", SqlDbType.NVarChar, 255).Value = filter;
cn.Open();
using (IDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
}
}
Notice that I was also able to "stack" the creation of the cn and cmd objects, and thus reduce nesting and only create one scope block.
Finally, a word of caution about using the yield return code in this specific sample. If you call the method and don't complete your DataBinding or other use right away it could hold the connection open for a long time. An example of this is using it to set a data source in the Load event of an ASP.NET page. Since the actual data binding event won't occur until later you could hold the connection open much longer than needed.
Microsoft's Patterns and Practices libraries are an excellent approach to handling database connectivity. The libraries encapsulate most of the mechanisms involved with opening a connection, which in turn will make your life easier.
Your understanding of using is correct, and that method of usage is the recommended way of doing so. You can also call close in your code as well.
Also : Open late, close early.
Don't open the connection until there are no more steps left before calling the database. And close the connection as soon as you're done.

Categories

Resources