Alternative to setting database connection from file - c#

I have a web service which invokes 2 different web methods.
One of the methods uses a SQL server connection and the other uses DB2.
The ODBC connection can talk to both a DB2 database and SQL server however the SQL has to be designed slightly differently for each method hence the option to switch the connection.
Right now I have a solution in place that is reading a string value from a text file stored on the server.
So if the string is SQL it uses the SQL connection string and ODBC uses the ODBC connection string.
Is there a more efficient way of doing this, without having to read the file in every time a web method is called as I am concerned that in the live environment, there will be bulk loads of data getting sent. So my concern is in the speed and performance of using this method.
Example of how I have implemented this -
String DBconSQL = "SQL-connection-string";
String DBconODBC = "ODBC-connection-string";
string connection = System.IO.File.ReadAllText(#"filePath");
[WebMethod]
public string stringRETURN(string connection)
{
if(connection == "SQL")
{
string con = "DBconSQL";
string sql = "SQL"
}
if(connection == "ODBC")
{
con = DBconODBC;
sql = "ODBC SQL";
}
//Do stuff here
}

Why don't you just store the value of each in memory after the first file read or just store them in the code.
i.e.
static class Globals
{
public static string DB2ConnStr = String.Empty;
public static string MSSQLStr = String.Empty;
}
You can read and write these from anywhere and they will persist as long as the server is up (i.e. the app is running in an app domain)
You should also (hopefully) be aware of the security concerns of storing plain text credentials either in code or text docs and (if this is for production) provide some form of encryption / security / reduce user permissions of the account that is being used to access the database ;)

Related

Microsoft Exchange Transport Agent

I am building a transport agent for Microsoft Exchange server. The logic I have implemented so far works. Now, I want to store some of the variables in DB. I have opted for a repository pattern and when I try to extract a connection string from App.Config file I am receiving a NullReference Exception:
public class ConfigRepository : IConfigRepository, IDisposable
{
private string configString = System.Configuration.ConfigurationManager.ConnectionStrings["citadelEAPEntities"].ConnectionString;
// private string configString = "..."; here I tried to write the string directly .
private string configValProc = "[dbo].[GetConfigValue]";
private SqlConnection connection;
public ConfigRepository()
{
connection = new SqlConnection(configString);
}
// other logic and implementation of interfaces
}
The same class is implemented in a test console app, which works fine (with the same connection string stored in the same manner in the app.config file).
I cannot understand the reason for this exception. The transporter agent class instantiates a ConfigRepository class within a 'using' statement and the moment it reaches the constructor function upon the initialization of the connection string variable via config manager an exception gets thrown. Obviously when I use the connection string in a hard coded manner everything works just fine.
Is the transporter agent assembly somehow limited while referencing other assemblies (such as System.Configuration) ? Just weird.
Transport Agents run under the security context of NetworkService so its most likely that it doesn't have enough rights to load the assembly from the location your referencing it from. If you use something like process monitor https://learn.microsoft.com/en-us/sysinternals/downloads/procmon your should be able track the process etc.

Firebird ConnectionString Change during runtime

I'm working on an app that has a live network database and a contingency local database, and it detects whether the live network db is accessible, and, if not, it times out after three seconds, changing the connectionstring to the local contingency database.
Following tips here on SO, I managed to alter the connectionstring on app.config during run time and reload the settings.
This is the method the app calls when a change on the connection string is needed:
public static void ChangeConnectionString(string connectionstring)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
connectionStringsSection.ConnectionStrings[0].ConnectionString = connectionstring;
var connectionStrings = config.ConnectionStrings;
foreach (ConnectionStringSettings connectionString in connectionStrings.ConnectionStrings)
{
connectionString.ConnectionString = connectionstring;
}
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
PDV_WPF.Properties.Settings.Default.Save();
PDV_WPF.Properties.Settings.Default.Reload();
//Ensures the configuration is saved and reloaded.
FbConnection.ClearAllPools();
//Closes all currently open connections which might be using the old connection string.
Debug.WriteLine("==========Ran ChangeConnectionString");
Debug.WriteLine("==========FDBConnString is:");
Debug.WriteLine("==========" + PDV_WPF.Properties.Settings.Default.FDBConnString);
After I disconnect my computer form the network, whenever I check the current FDBConnString, it correctly points to the local contingency database. However, on the very next line, when it tries to run a query, I get the following exception:
Inner Exception 1:
IscException: Unable to complete network request to host "dbserver".
Inner Exception 2:
SocketException: Este host não é conhecido //(This host is unknown)
Full exception details: https://pastebin.com/3syLvsQf
It seems that, even after I successfully change the connection string, and successfully reload the application config file, it still tries to open a connection using the old connection string. Even if I call Debug to print the current Properties.Settings.Default.FDBConnString right on the line above the call for FbConnection.Open(), it shows the new string rather than the incorrect, old one.
Any insights on what might be going on?
I found what was the issue.
I am instancing a inherited table adapter from the generated xsd file. When I declare a table adapter on my class it also inherits the connection string stored on app.config at the time of declaration. So it doesn't matter if I change app.config, as the declared table adapter is already stuck with the previous connection string.
So, the solution was, rather than changing the connection string stored on app.config, I just had to change the connection string on the declared table adapter:
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
or
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
Both ContingencyDB and NetworkDB are strings stored on app.config as a user-scoped string, which can be changed via a given "Settings" window presented to the user.

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.

How to connect to local SQL database?

As of now I've been given a piece of software that reads XML files and presents these graphically, to give the user some overview to the events these files describe.
The crux as of now is that one of the engineers using the software has requested that all the data you load into the program should be possible to save to a database.
My pickle is as follows:
public void addToDBO(List<List<EventElement>> insertList)
{
SqlConnection s1 = new SqlConnection();
s1.ConnectionString = filePath;
s1.Open();
SqlCommand command = new SqlCommand();
command.Connection = s1;
foreach (List<EventElement> item in insertList)
---------------------SNIP----------------------------
//Adding-data-to-database logic
I mean to write the loaded data into a database deployed localy, but the the problem is that it does not accept my hamhanded methods of simply adding the database's filepath as the filepath string.
So, to summarize:
How do I correctly connect to a database situated on my C:/?
Thank you in advance.
You do not simply pass a file path. The connection string needs to follow a certain convention. For example
Provider=SQLNCLI10;Server=.\SQLExpress;AttachDbFilename=c:\asd\qwe\mydbfile.mdf;
Database=dbname;Trusted_Connection=Yes;
See http://www.connectionstrings.com/sql-server/ for more

How to Connect to SQL Server Programmatically in C#?

I have developed a program (C#) which creates a SQL database using this code:
string SQLCreation = "IF NOT EXISTS (SELECT * FROM master..sysdatabases WHERE Name = 'x') CREATE DATABASE x";
SqlConnection PublicSQLDBCreationConnection = new SqlConnection(connectionString);
SqlCommand PublicSQLDBCreation = new SqlCommand(SQLCreation, PublicSQLDBCreationConnection);
try
{
PublicSQLDBCreationConnection.Open();
PublicSQLDBCreation.ExecuteNonQuery();
PublicSQLDBCreationConnection.Close();
}
//'then creates a table and so on
Now I want to have a client application which connects to this database (via LAN) WITHOUT using IP or computer name. How is that possible? Is it possible do this and have a dataset while not mentioning IP Adr. or computer name?
P.S. Don't Worry Guys, I simplified my code just for your view, I have made sure that SQL injection or other attempts won't happen.
Also I have to say that My Reason for not mentioning servername or IP is that I want to mass deploy my Application on many Networks
You could use SqlDataSourceEnumerator to get a list of all Sql Servers that are visible and browsable. This is not a good technique, since you could get an instance that you don't have the right to create a database on it, but you could still try something with that.
var enumerator = SqlDataSourceEnumerator.Instance;
foreach (DataRow row in enumerator.GetDataSources().Rows)
{
var serverName = row["ServerName"];
var instance = row["InstanceName"];
// build a connection string and try to connect to it
}

Categories