System.Data.SqlClient.SqlConnection unexpected result in Open() Method with incomplete ConnectionString - c#

When calling the Open() method on a SqlConnection instance that got passed an incomplete connection string, the method does not throw an exception.
I have created the following example to showcase my problem.
var success = true;
var connectionStrings = new[]
{
"Integrated Security=SSPI;",
"Initial Catalog=awdemo;Integrated Security=SSPI;",
"Data Source=.\\sql2016;Initial Catalog=awdemo;Integrated Security=SSPI;"
};
foreach (var connectionString in connectionStrings)
{
var conn = new SqlConnection(connectionString);
try
{
conn.Open();
}
catch (Exception)
{
success = false;
}
finally
{
conn.Close();
Console.WriteLine($"{connectionString} - Success = {success}");
}
}
Result:
Integrated Security=SSPI; - Success = True
Initial Catalog=awdemo;Integrated Security=SSPI; - Success = True
Data Source=.\sql2016;Initial Catalog=awdemo;Integrated Security=SSPI; - Success = True
I would expect conn.Open() to throw an exception for the first two connection strings, since both of them are incomplete and not valid.
Why is there no exception thrown?
EDIT: as pointed out by Steve in the comments an exception is not thrown because the component connects to my default instance of SQL Server when not providing the server information.
Is there a way to force the SqlConnection component to throw an error on incomplete connection strings? In the application it is possible and allowed to create incomplete connection strings.

There's no practical way to fully validate this. You could have a connection string that has all of the components you expect, including a valid server and database name, but it's the wrong server or wrong database.
So if the expectation is that the class should fail on conn.Open() if the connection string is incorrect (not invalid, but incorrect), you can't completely achieve that.
Does it matter? Imagine a few scenarios, all of which include incorrect connection strings:
The connection string is "blarg!" and so attempting to open the connection throws an exception.
The connection string doesn't contain a server or database name. You can open the connection but when you try to execute some command it fails.
The connection string contains a server and database name, but it's the wrong server or database. It fails for the same reason as 2.
In each of the scenarios, what's the first thing you're going to do? You're going to look at the exception. Regardless of which line throws it, you're going to quickly deduce that you have the wrong connection string.
So a "validation" which can't actually validate the connection string before you open it is just going to add work. If the connection string is wrong, that truly is an "exceptional" condition so it's probably better to just let the code throw an exception where it does. You'll find the problem quickly.
All of that aside, suppose you just really want to be sure that your connection contains a server name and a database name before you try to open it. You could write an extension method like this:
// Maybe give it a better name.
public static void ValidateThatConnectionHasDataSourceAndDatabase(this SqlConnection connection)
{
if (string.IsNullOrEmpty(connection.DataSource))
throw new Exception("The connection has no datasource");
if (string.IsNullOrEmpty(connection.Database))
throw new Exception("The connection has no database");
}
After you create the connection and before you open it, call conn.ValidateThatConnectionHasDataSourceAndDatabase();

Related

Check Database ConnectionState

I'm connecting to Firebird Database using C#
I can't find where to check the ConnectionState to the database
If I make new fbConnection inside project it's easy to check it by fbConnection.ConnectionState
but I have made this connection with wizard and it's saved in App.config file
I tried to use System.Configuration.ConfigurationManager but it doesn't have ConnectionState
So how can I check connection state that defined in App.config file.
It seems that you don't understand how this thing (the connection) works or what it is. The ConfigurationManager class just helps you to retrieve the connectionstring (note the word string. It is just a string nothing more).
With this string you can build your real instance of an FBConnection and try to open that connection. Now you could check the ConnectionState.
So
string connectionString = ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString;
using(FbConnection myConnection = new FbConnection(connectionString))
{
// At this point the myConnection instance is certainly closed so
// it is total useless to check the ConnectionState
myConnection.Open();
// At this point the myConnection instance is certainly opened,
// otherwise you get an exception and your code cannot contine,
// so also here it is useless to check the ConnectionState
// however...
if(myConnection.ConnectionState == ConnectionState.Open)
{
.... do your stuff with the connection.....
}
}
For this code to work you need to have in your App.Config the appropriate section where you store the details required to connect to your database under the symbolic name "MyConnection"
<connectionStrings>
<add name="MyConnection" connectionString="Data Source=localhost;
Database=YourDatabaseFile.fdb;
User=YourUserName;
Password=????whatever???;
Pooling=True" />
</connectionStrings>
So I really have never needed to check the connection state of a connection. The only possible use if this property is when you want to keep a global connection instance and in various part of your code you need to check the ConnectionState before trying to open or close this global instance. This scenario is not the best way to work with a disposable object like the connection that should be opened for the shortest period of time possible and the immediately destroyed (disposed) And exiting from the using block disposes the connection.
Check out this link, it may be useful for you.
https://sourceforge.net/p/firebird/NETProvider/ci/0475d606c597498a99be50393646c1c92d773dd4/tree/examples/ASP.NET/web.config

Best way to handle connection when calling a function from a Console App or SQLCLR object with ("Context Connection=true")

I have the following type of code in my data layer, which can be called from a console app, windows app, etc, with the proper connection string being read from the corresponding caller's App.Config file:
public static udsDataset GetDataset(int datasetID)
{
string connectionString =
ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string sql = #"select * from Dataset WHERE DatasetID=#datasetID";
using (SqlConnection conn = new SqlConnection(connectionString))
{
// Dapper query:
return conn.Query<udsDataset>(sql, new {datasetID } ).First();
}
}
I now want to call this same code from a SQLCLR stored procedure (within the database where these tables exist), where you would typically use a context connection:
using(SqlConnection connection = new SqlConnection("context connection=true"))
{
connection.Open();
// etc etc etc
}
The most obvious approach that comes to mind is to overload the function:
public static udsDataset GetDataset(int datasetID)
{
string connectionString =
ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionString))
{
return GetDataset(datasetID, conn);
}
}
public static udsDataset GetDataset(int datasetID, SqlConnection conn)
{
// caller is responsible for closing and disposing connection
string sql = #"select * from Dataset WHERE DatasetID=#datasetID";
return conn.Query<udsDataset>(sql, new {datasetID } ).First();
}
So apps with an App.Config could call the connection-less version and SQLCLR could call the version requiring a SqlConnection.
This "seems ok", but having to write the exact same style of overload for every single similar function makes it feel wrong.
Taking the question (and comments on it) at face-value, why do you need:
the option of passing in an existing connection when calling from a SQLCLR procedure
? You should treat the Context Connection the same as any other connection with regards to Open and Dispose. It sounds like you are thinking that the SqlConnection, when using a Connection String of "Context Connection = true;", needs to be opened only once and then not disposed until completely done, whereas you would Open / Dispose of it several times otherwise. I don't see any reason to have differing behavior in these two scenarios.
All of that aside, how to best handle detecting the change in environment (between Console App and SQLCLR object)? You have two choices, both being probably easier than you are expecting:
Make no changes to the app code, but rely on an additional config file:
You can create a file named sqlservr.exe.Config in the C:\Program Files\Microsoft SQL Server\MSSQL{SqlVersion}.{SqlServerInstanceName}\MSSQL\Binn folder (e.g. C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn, where the 11 in MSSQL11 is for SQL Server 2012). The format of this file, as should probably be expected, is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="CoolioAppDB" connectionString="Context Connection = true;" />
</connectionStrings>
</configuration>
This might be considered "cleaner" code, but does introduce an external dependency that your DBA might be ok with, might dislike but tolerate, or might ask your manager to write you up for ;-).
Make a very minor change to the app code, but don't rely on an additional config file:
You can easily auto-detect whether or not you are currently running in SQL Servers's CLR host by using the IsAvailable property of the SqlContext class. Just update your original code as follows:
string connectionString = "Context Connection = true;"; // default = SQLCLR connection
if (!SqlContext.IsAvailable) // if not running within SQL Server, get from config file
{
connectionString =
ConfigurationManager.ConnectionStrings["CoolioAppDB"].ConnectionString;
}
This usage, by the way, is noted in the "Remarks" section of that linked MSDN page for the IsAvailable property.

Database connection succeeds for non-existent databases

Looks like SQLite database connection doesn't actually try to open database connection when I call Open() function. Here's a simple test:
var factory = DbProviderFactories.GetFactory("System.Data.SQLite");
connection = factory.CreateConnection();
connection.ConnectionString = "data source=NonExistentDB.db3";
conn.Open();
The above code does not generate any kind of exception. Moreover, the connection state is Open after this. Is there a way to do "Test Connection" that would physically establish a connection with the database?
Change to
connection.ConnectionString = "data source=NonExistentDB.db3;FailIfMissing=True"
Without the last argument, it will simply create a new database if the file is not found.

Checking whether a database is available?

My problem involves checking if I have a valid database connection before reading from the database. If the database is down I'd like to write to a xml file instead. I have the location of the database (if it's up) at runtime so if the database was working I can create a new sqlConnection to it.
Use a typical try...catch...finally structure, and based on the specific exception type and message, decide whether you want to write to xml or not.
try
{
SqlConnection connection = new SqlConnection(DB("Your DB Name"));
connection.Open();
}
catch (Exception ex)
{
// check the exception message here, if it's telling you that the db is not available. then
//write to xml file.
WriteToXml();
}
finally
{
connection.Close();
}
I would just use something like:
using(SqlConnection conn = new SqlConnection(c)) {
conn.Open();
}
It will throw an exception if invalid. You could write to the xml in the exception.
An easy way would be to execute a simple query and see if an error occurs:
For Oracle:
SELECT * FROM DUAL
For SQL Server
SELECT 1
Basicly just some kind of relatively "free" query that will let you know that the database is up and running and responding to requests and your connection hasn't timed out.
You cannot really tell whether the DB is up and running without actually opening a connecting to it. But still, connection might be dropped while you're working with it, so this should be accounted for.

C# MySQL Connection problems

I'm trying to connect a C# application (using Visual C# 2008 Express Edition) to a remote MySQL server. I have the drivers for this, but when I followed the tutorials (including adding the pooling and connection reset properties), I get an error that: Object reference not set to an instance of an object. I've included the two lines of code that should be making a connection. The error is thrown on the second line.
MySqlConnection connect = new MySqlConnection("database=d*******;Data Source=mysql.netfirms.com;user id=*******;pwd=*****;pooling=false;connection reset=false");
connect.Open();
I'd try setting the connection string outside of the constructor to help narrow down the issue:
MySqlConnection connect = new MySqlConnection();
//Do you get the null exception in this next line?
connect.ConnectionString = "your conn string here";
connect.Open(); //-> If you get the exception here then the problem is with the connection string and not the MySqlConnection constructor.
If you do get the exception in the connect.ConnectionString = ... line, then the problem is with the driver and sounds like you need to reinstall it.
I would also try a simpler connection string, without the pooling and reset keys.
Can you post more code? The exception line is probably a bit off due to compiler optimization or related. Constructors must return an object or throw an exception. It is impossible to say
MyType item = new MyType();
Debug.Fail(item == null); // will never fail.
The null reference is probably on the line just above your instantiation.

Categories