My Singleton is throwing a StackOverflowException, but yesterday it worked fine and the unique change was the database in the Connection String. It is a console application and the debug is very complicated:
class OracleSingleton
{
private static OracleConnection instance;
private OracleSingleton() { }
public static OracleConnection Instance
{
get
{
if (instance == null)
{
try
{
instance = new OracleConnection(ConfigurationManager.ConnectionStrings["OracleConnection"].ConnectionString);
}
catch (Exception ex)
{
LogHelper.WriteMessage("Error trying to create a new connection. - " + ex.Message.ToString() + " - " + ex.InnerException.ToString().Trim());
}
}
return instance;
}
}
}
My App.config:
<configuration>
<connectionStrings>
<add name="OracleConnection" connectionString="Password=somepassword;Persist Security Info=True;User ID=someuser;Data Source=DATABASE01"/>
</connectionStrings>
//Some stuff
</configuration>
Can you guys show me what is wrong and why yesterday it worked fine?
EDIT:
I use the Singleton to do a lot of things. I Know that the problem is in the singleton because my application shows the StackoverflowException without log anything, who is one of the places where I use the Singleton. Below, my LogHelper.WriteMessage method, who is called at the first line of program to say" Hi, the application is running right now ":
public static void WriteMessage(string info)
{
using (OracleConnection conn = OracleSingleton.Instance)
{
using (OracleCommand cmd = new OracleCommand("INSERT INTO TB_LOG (DT_LOG, ID_PERMISSAO, ID_USUARIO, NM_USUARIO, DS_LOG) VALUES (TO_CHAR (SYSDATE, 'MM-DD-YYYY HH24:MI:SS'), 5025, 5025, 'IMPORTADORCAIXA', '" + info + "')", conn))
{
try
{
conn.Open();
cmd.ExecuteNonQuery();
} catch (Exception ex)
{
Console.WriteLine(DateTime.Now + " - Erro ao conectar com o banco. por favor, verifique o erro: " + ex.Message.ToString() + ", " + cmd.CommandText.ToString());
}
}
}
new LogHelper();
eventLog.WriteEntry(info);
Console.WriteLine(DateTime.Now + " - " + info);
}
Your "singleton" is indeed recursive on some paths. What happens if this line
instance = new OracleConnection(ConfigurationManager.ConnectionStrings["OracleConnection"].ConnectionString);
throws exception, for example if connection string is invalid? You log that exception with WriteLog which again references singleton with
using (OracleConnection conn = OracleSingleton.Instance)
So if connection string is invalid, or connection creation constantly fails for other reason - you go into recursion and eventually end with StackOverflowException when stack space is exhausted.
By the way, with
using (OracleConnection conn = OracleSingleton.Instance)
you also dispose your connection, making it unusable for subsequent invocations.
Best way to resolve it is to just get rid of singleton, there is no need for it. It's bad practice to have global connection - just create it every time you need it and dispose (close) when you are done with it. Connection pool will manage the rest for you.
If you don't want to do serious refactoring for some reason, at least change to something like this:
public static OracleConnection Create() {
// no need to catch any exceptions here
return new OracleConnection(ConfigurationManager.ConnectionStrings["OracleConnection"].ConnectionString);
}
And use as you already do:
using (OracleConnection conn = OracleSingleton.Create())
Related
I am using C# in Visual Studio 2019, with Xamarin.Forms, and SQl in SSMS 2018 and have the below code (where [] is used to replace unneccessary information)
try
{
using(SqlConnection connection = new SqlConnection())
{
connection.ConnectionString = "Server=[ServerName]; Database=[DatabaseName]; User Id= [UserID]; Password=[Password]";
connection.Open();
SqlCommand command = new SqlCommand("SELECT * from [TableName]", connection);
[Does stuff here]
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex)
}
When I run this, it hangs indefinitely at connection.Open(). Debug mode continues to run and appears to move on from Connection.Open(), but never reaches the next line.
I have attempted this with different versions of the ConnectionString, using different databases and with Trusted_Connection=true instead of specifiying the username and password but they have made no difference. Adding Connection Timeout = 5 to the connectionString has no effect.
I believe it is probably an issue with my settings in SQL but as I am a novice with this I have no idea where to start and the similar forums posts I have checked have been given answers along the lines of Connection Timeout (Connection.open for hangs indefinitely, no exception is thrown) or never got answered.
Any advice would be greatly appreciated.
Can you log into SSMS with the credentials that are in the connection string?
Otherwise I've had luck making sure the connection isn't already open or broken first:
if (connection.State == ConnectionState.Closed || connection.State == ConnectionState.Broken)
{
connection.Open();
}
Can you try code changing line as per below -
connection.ConnectionString = "Data Source=[ServerName]; Initial Catalog=[DatabaseName]; Integrated Security=SSPI;"
A workaround to this problem is to pass in a cancellation token instance as shown below,
public async Task<IEnumerable<Toy>> ShowToybox(CancellationToken t)
{
// notice I turned this into an async operation.
// Reason is to let this operation to find its way out if something happens
var connString = "Server=xyz; Connection Timeout=250";
//Timeout might not happen, if that is not the case see below..
using(SqlConnection connection = new SqlConnection(connString))
{
if ( t.IsCancellationRequested) {
t.ThrowIfCancellationRequested();
}
// await query here. To fetch records from the toybox table
return matches;
}
Main issue is that you cannot trust connection.State
To get this working, code that consumes this method should expect something might go wrong.
class Program
{
static void Main()
{
var box = new ToxBox(); //it has method shown above
var s = new CancellationTokenSource();
s.CancelAfter(400); //it prevents method from hanging
var task = Task.Run(() = box.ShowToybox(s.Token));
try
{
task.Wait(s.Token);
var myToys = task.Result();
Console.WriteLine($"I have {myToys.Count()} toys");
}
catch (Exception e)
{
Console.WriteLine("Something happened!");
}
finally
{
s.Dispose(); //this is important
}
}
}
See https://learn.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads
Currently I am doing an assignment in which I need to visit database of n number of servers to fetch some results.I have achieved this by iterating through the list of servers and raising tasks each one for each server in the collection. The task calls a function which basically makes an connection with the database,run query and disconnect from database.
My question is I am doing right by making a new connection on each polling with the database and closing it everytime or is this would be the best approach to keep a db connection open and fetch the result and then keep it open on next polling iteration.
PollingServerTimer() is being called by timer everytime.My polling timer is 3 sec.
Something like this :
private void PollingServerTimer(object sender, ElapsedEventArgs e)
{
foreach (var item in ServerOperationCollHandler)
{
if (item.RebootStatus != true)
{
PushItemIntoQueue(item);
}
}
}
public void PollingServerQueue()
{
while (isRunning)
{
this.waitHandle.WaitOne();
lock (syncRoot)
{
if (ServerQueue.Count > 0)
{
ServerOperationDataModel obj;
try
{
ServerQueue.TryDequeue(out obj);
Task GetCountFromDbTask = new Task(() => GetCountFromDb(obj));
GetCountFromDbTask.Start();
this.waitHandle.Reset();
}
catch (Exception ex)
{
MessageBox.Show("Problem encountered while finding iterim and recovery count");
isRunning = false;
break;
}
}
}
}
}
public void GetCountFromDb(ServerOperationDataModel obj)
{
ServerOperationDataModel serverObject = (ServerOperationDataModel)obj;
DataBaseHandler dbHandler = new DataBaseHandler(serverObject.DataBaseIP, serverObject.DataBasePort, serverObject.DataBaseName, serverObject.DataUserName, serverObject.DataUserPassword);
int attempts = 0;
do
{
try
{
dbHandler.connect();
}
catch (Exception ex)
{
break;
serverObject.DataBaseConnectionStatus = false;
log.Error("Connection attempt " + attempts + " failed.Retrying connection. Exception details :" + ex.ToString());
attempts++;
}
} while (attempts < _connectiontRetryAttempts && !dbHandler.isConnected());
if (dbHandler.isConnected())
{
/*Fetch Result and then get disconnect*/
dbHandler.disConnect();
}
else
{
//string msgLog = "Server : " + obj.ServerComponentIdentifier + " | " + obj.IPstring + "Connection cannot be established with the DB: " + obj.DataBaseIP + " | "+ obj.DataBasePort + " | " + obj.DataBaseName + " after a series of retries";
//LoggerUpdate.LogMessage(msgLog, LOGTYPE.POLLINGDATABASE, LoggerUpdate.ReturnLogDisplayObject(DateTime.Now, obj.ServerComponentIdentifier + "|" + obj.IPstring, Convert.ToInt16(LOGTYPE.POLLINGDATABASE), obj, msgLog));
}
}
I would not be concerned at all. Assuming you connect to the SQL Server (or a similar, enterprise DBMS), database connections are pooled at the client side which means that establishing the connection is costly only the first time the client connects to a particular db (formally: to a new, previously unseen connection string) and then each connection to the same database costs almost nothing.
If it hadn't been for pooling, applications servers would not be able to handle hundreds of concurrent browser connections that query the same data source. You would need much more than a connection every 3 seconds to cause any risk of depleting server or client resources.
You can read more on how pooling works
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling
A side note: You should polish your code a little bit.
For example, you have
GetCountFromDb(ServerOperationDataModel obj)
but then
ServerOperationDataModel serverObject = (ServerOperationDataModel)obj;
Why would you need to cast the obj to another variable of the very same type?
In the catch clause, you have break and some code below it which looks unreachable.
Take a look at the .NET SqlDependency object. This allows you to register a query with a database and, using an OnChange handler, receive notification whenever the result of the query changes.
I'm trying to make a program with a login system
I'm new to this but I have been working 8 hours straight trying to fix this.
This is the error code I get
+ ServerVersion 'con.ServerVersion' threw an exception of type 'System.InvalidOperationException' string {System.InvalidOperationException}
Here's my code
private void LogB_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("Data Source=Myip;user id=MyId;database=MyDb;password=MyPw;persistsecurityinfo=True");
SqlDataAdapter sda = new SqlDataAdapter("Select * From login where navn='"+ TULog.Text + "' and pw='" + TPLog.Text + "'",con);
try
{
con.Open();
}
catch (SqlException ex)
{
MessageBox.Show(ex.ToString());
throw ex;
}
finally
{
con.Close();
}
}
}
}
Sorry If this seems like some crap but I'm a guy who's trying to learn :p
This exception is telling you that there was an attempt to access the con.ServerVersion property while the SqlConnection was closed.
From MSDN on the SqlConnection.ServerVersion property:
InvalidOperationException - The connection is closed. ServerVersion was called while the returned Task was not completed and the connection was not opened after a call to OpenAsync.
The code you show above does not show a call to this property, you must be doing so somewhere else. Regardless, the connection needs to be open prior to doing so.
I have an app that connects to a MYSQL database through the entity framework. It works 100% perfectly, but I would like to add a small piece of code that will test the connection to the database upon app startup.
I had the idea of simply running a tiny command to the database and catching any exceptions, however if there is a problem (eg App.Config missing or Database server down) the app takes a huge amount of time to run this code and then throw the exception (~1 min). I imagine this is due to connection timeouts etc but I have fiddled with such properties to no avail.
Would anyone be able to assist with any ideas as to where to go?
Are you just wanting to see if the DB connection is valid? If so take a look at the
using (DatabaseContext dbContext = new DatabaseContext())
{
dbContext.Database.Exists();
}
http://msdn.microsoft.com/en-us/library/gg696617(v=vs.103).aspx
and for checking if a server machine is up, DB server or web services server , try this:
public PingReply Send( string hostNameOrAddress )
http://msdn.microsoft.com/en-us/library/7hzczzed.aspx
The solution as #Danilo Breda pointed out is to call the DbContext.Database.Connection.Open()
It is tested with EF6.
My implementaion:
public static bool CheckConnection()
{
try
{
MyContext.Database.Connection.Open();
MyContext.Database.Connection.Close();
}
catch(SqlException)
{
return false;
}
return true;
}
In EntityFramework Core you can simply call: Database.CanConnect();.
(using EF Core 2.2.1)
Summary: Determines whether or not the database is available and can be connected to.
Note that being able to connect to the database does not mean that it is up-to-date with regard to schema creation, etc.
I use this code for my project:
private bool TestConnectionEF()
{
using (var db = new SistemaContext())
{
db.Database.Connection.Open();
if (db.Database.Connection.State == ConnectionState.Open)
{
Console.WriteLine(#"INFO: ConnectionString: " + db.Database.Connection.ConnectionString
+ "\n DataBase: " + db.Database.Connection.Database
+ "\n DataSource: " + db.Database.Connection.DataSource
+ "\n ServerVersion: " + db.Database.Connection.ServerVersion
+ "\n TimeOut: " + db.Database.Connection.ConnectionTimeout);
db.Database.Connection.Close();
return true;
}
return false;
}
}
I know this is an old question, but here is my answer for anyone looking for a newer implementation.
I was able to use CanConnect to check the status of the database:
_database.Database.CanConnect();
# Async too
await _database.Database.CanConnectAsync(_cancellationTokenSource.Token);
I hope this helps others as well. Cheers!
I used the answer from #Sandor and did an extension method to use with EntityFramework Core.
Here's the code:
using Microsoft.EntityFrameworkCore;
using System.Data.Common;
namespace TerminalInventory
{
public static class ExtensionMethods
{
public static bool TestConnection(this DbContext context)
{
DbConnection conn = context.Database.GetDbConnection();
try
{
conn.Open(); // Check the database connection
return true;
}
catch
{
return false;
}
}
}
}
Now you just have to call:
if (!context.TestConnection())
{
logger.LogInformation("No database connection. Check the connection string in settings.json. {0}", configuration["connectionString"]);
return;
}
I am using the following code for MS SQL connection. Maybe, it will be useful for MySQL too. You don’t even need to use an EF or EF Core.
public bool IsDbConnectionOK()
{
SqlConnectionStringBuilder conStr = new SqlConnectionStringBuilder
{
DataSource = ButtonServerName.Text, // <-- My Form Elements
InitialCatalog = ButtonDBName.Text, // <-- My Form Elements
UserID = EditUserName.Text, // <-- My Form Elements
Password = EditPassword.Text, // <-- My Form Elements
IntegratedSecurity = false,
ConnectTimeout = 30
};
string connectionstring = conStr.ToString();
try
{
using (System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(connectionstring))
{
connection.Open();
return true;
}
}
catch (System.Data.SqlClient.SqlException ex)
{
MessageBox.Show(ex.Message + Environment.NewLine +
"Error line: " + ex.LineNumber + Environment.NewLine +
"Procedure name: " + ex.Procedure);
return false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
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 54
You 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.
This is not a bug in the VM. Here is your offending line:
private static readonly DbConnectionFactory _connectionFactory;
Internal to this we have the connection pool. Which stores a reference to the exception that occurred.
This opens up a race condition when performing multi-threading.
How do we prove this?
Logically if you use different connection pools then we will not have this race condition. So I reran the same test with a different data source specified in the connection string for each thread. The exceptions are now showing up correctly.
This is really a case of the connection pool not being thread safe.
OK, I managed to reproduce this (VS2008, FX3.5SP1, dual core) both inside and outside(*) the debugger. And after altering your catch logic a little it even is reliably reproducable. And, like Gregory mentioned, it is the same exception instance thrown in both threads.
This should be totally impossible at
the VM level.
Where did you get that idea?
Both threads are trying to connect through the connection pool. I don't know anything about how the Pool works, but I'll take a guess: It is serializing the 2 simultaneous requests. That sounds like being nice to the Server. And then when the attempt fails it has 1 exception and 2 waiting threads.
I too would have expected the CLR or the ConnectionPool to duplicate the exception and prepend 2 separate stacktraces but instead it merges the 2 calling traces.
So I think your bug could very well be feature, status: by design.
Because it is not really an 'intermingled' stacktrace but more of a deliberately Y-shaped one. It does not look accidental.
It would be nice if somebody found a reference for this behaviour though. Right now I'm not sure if this is a CLR or a ConnectionPool 'feature'.
(*) Edit: I think I saw it outside the debugger once, but now I'm unable to reproduce that. So it could be a debugger or a timing issue.
You are getting the same exception thrown. I don't understand why however. Have a look at the output window, notably that exception1 == exception2.
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(20000);
threadTwo.Join(20000);
Debug.WriteLine("Same?" + (exception1 == exception2));
}
catch (Exception e)
{
Debug.WriteLine("error main" + e);
}
}
static Exception exception1;
static void GetConnectionOne()
{
try
{
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
{
conn.Open();
}
}
catch (Exception e)
{
Debug.WriteLine("Error Con one" + e);
exception1 = e;
}
}
static Exception exception2;
static void GetConnectionTwo()
{
try
{
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
{
conn.Open();
}
}
catch (Exception e)
{
Debug.WriteLine("Error Con two" + e);
exception2 = e;
}
}
}
Edit: The below was my original response.
It's very likely your "random" filenames are similar, if not the same, as they will sometimes be called within very close timeframes. Often, when you have a problem that randomly appears, and you have a Random.Next call, it should be the first place you look.