Ok this looks like a major fundamental bug in .NET:
Consider the following simple program, which purposely tries to connect to a non-existent database:
class Program { static void Main(string[] args) { Thread threadOne = new Thread(GetConnectionOne); Thread threadTwo = new Thread(GetConnectionTwo); threadOne.Start(); threadTwo.Start(); } static void GetConnectionOne() { try { using (SqlConnection conn = new SqlConnection("Data Source=.\\wfea;Initial Catalog=zc;Persist Security Info=True;Trusted_Connection=yes;")) { conn.Open(); } } catch (Exception e) { File.AppendAllText("ConnectionOneError.txt", e.Message + "\n" + e.StackTrace + "\n"); } } static void GetConnectionTwo() { try { using (SqlConnection conn = new SqlConnection("Data Source=.\\wfea;Initial Catalog=zc;Persist Security Info=True;Trusted_Connection=yes;")) { conn.Open(); } } catch (Exception e) { File.AppendAllText("ConnectionTwoError.txt", e.Message + "\n" + e.StackTrace + "\n"); } } }Run this program and set breakpoints on the catch blocks. The DBConnection object will attempt to connect for 15 seconds (on both threads), then it will throw an error. Inspect the exception's stack trace, and the stack trace will have TWO call stacks intermingled, as follows:
at System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject) at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) at System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject) at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject) at System.Data.SqlClient.SqlConnection.Open() at ZoCom2Test.Program.GetConnectionOne() in C:\src\trunk\ZTest\Program.cs:line 38 at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) at System.Data.SqlClient.SqlConnection.Open() at ZoCom2Test.Program.GetConnectionTwo() in C:\src\trunk\ZTest\Program.cs:line 54You may have to try it several times to get this to happen, but I'm getting this to happen right now on my machine. How is this possible? This should be totally impossible at the VM level. It looks like the DBConnection.Open() function is simultaneously throwing the same exception on two threads at once, or something bizarre like that.
Try this instead, and see what happens:
class ThreadingBug { private const string CONNECTION_STRING = "Data Source=.\\wfea;Initial Catalog=catalog;Persist Security Info=True;Trusted_Connection=yes;"; static void Main(string[] args) { try { Thread threadOne = new Thread(GetConnectionOne); Thread threadTwo = new Thread(GetConnectionTwo); threadOne.Start(); threadTwo.Start(); threadOne.Join(2000); threadTwo.Join(2000); } catch (Exception e) { File.AppendAllText("Main.txt", e.ToString()); } } static void GetConnectionOne() { try { using (SqlConnection conn = new SqlConnection(CONNECTION_STRING)) { conn.Open(); } } catch (Exception e) { File.AppendAllText("GetConnectionOne.txt", e.ToString()); } } static void GetConnectionTwo() { try { using (SqlConnection conn = new SqlConnection(CONNECTION_STRING)) { conn.Open(); } } catch (Exception e) { File.AppendAllText("GetConnectionTwo.txt", e.ToString()); } } }I believe there is a bug here, though it's neither major, nor fundamental. After working to narrow this down (and to do things like removing one thread), it looks like the same instance of the Exception class is thrown by the Connection Pool implementation on both threads (kudos to Gregory for discovering this). This sometimes shows up as a corrupt ("intermingled") stack trace, and sometimes simply as the same stack trace on both threads, even when the code is quite different between the two threads.
Commenting out one of the Thread.Start calls shows an entirely different stack trace, demonstrating that the odd part is in the connection pool implementation - the odd stack traces are being handed out by the connection pool, since both threads use the same connection string and credentials.
I've submitted a Connect issue on this at https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=522506 . Everyone should feel free to vote on how important (or unimportant) you feel it is, whether you can reproduce it, or whether you have a workaround. This will help Microsoft prioritize a fix.
Update:The Connect issue has been updated. Microsoft acknowledges it as a bug, and plans to fix it in a future release.
Thanks to nganju, Gregory, and everyone else who participated in solving this problem. It was indeed a bug, and it will be fixed, and it's because of us.