Entity Framework set connection string at runtime - c#

I have been trying to get this work for last couple of days with no success.
This is what I have done so far.
string providerName = "System.Data.SqlClient";
string serverName = serverIPAddress;
string databaseName = myDBName;
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.DataSource = serverName;
sqlBuilder.InitialCatalog = databaseName;
sqlBuilder.PersistSecurityInfo = true;
sqlBuilder.MultipleActiveResultSets = true;
sqlBuilder.UserID = "sa";
sqlBuilder.Password = saPassword;
string providerString = sqlBuilder.ToString();
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.Provider = providerName;
entityBuilder.ProviderConnectionString = providerString;
entityBuilder.Metadata = "res://*/TUModel.myModel.csdl|res://*/TUModel.myModel.ssdl|res://*/TUModel.myModel.msl";
myEntities ctx = new myEntities(entityBuilder.ConnectionString);
The constructor in entity class look like
public myEntities(string connectionString) : base("name=myEntities")
{
}
When I run there is no error. However if I delete 'myEntities' connection string from app.config, then it throws exception. If I leave it as it is then it ignores the connection string in the code and use the one in app.config.
Any help would be greatly appreciated.

Your context constructor isn't passing your connection string in, instead it is passing through a fixed value of name=myEntities. Change it to this:
public myEntities(string connectionString) : base(connectionString)
{
}

Related

Connecting to multiple SQL Servers dynamicly with C# Form?

I have some SQL Servers that is Identical exept for the data stored and i want to be able to change between them and if i add more i want to easy add them with a windows form.
I have done a database first and this is the connection string that was added to the App.config file. I changed the username and password for security reasons
<add name="MigrateDBFaktura3Entities"
connectionString="metadata=res://*/DB.ServerData.csdl|res://*/DB.ServerData.ssdl|res://*/DB.ServerData.msl;provider=System.Data.SqlClient;provider connection string="data source=FASTEC-ATTEST\SQLEXPRESS;initial catalog=MigrateDBFaktura5;persist security info=True;user id=**;password=**;MultipleActiveResultSets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
Is there a easy way to change where i should get the data from?
I was thinking to use a combobox where i could chose what SQL Server it should get the data from.
If i manualy change the connection string it works. but how do i do it with code?
you can utilize class EntityConnectionStringBuilder to build your connection string. refer more here https://msdn.microsoft.com/en-us/library/orm-9780596520281-01-16.aspx and Programmatic Connection Strings in Entity Framework 6
// Specify the provider name, server and database.
string providerName = "System.Data.SqlClient";
string serverName = ".";
string databaseName = "AdventureWorks";
// Initialize the connection string builder for the
// underlying provider.
SqlConnectionStringBuilder sqlBuilder =
new SqlConnectionStringBuilder();
// Set the properties for the data source.
sqlBuilder.DataSource = serverName;
sqlBuilder.InitialCatalog = databaseName;
sqlBuilder.IntegratedSecurity = true;
// Build the SqlConnection connection string.
string providerString = sqlBuilder.ToString();
// Initialize the EntityConnectionStringBuilder.
EntityConnectionStringBuilder entityBuilder =
new EntityConnectionStringBuilder();
//Set the provider name.
entityBuilder.Provider = providerName;
// Set the provider-specific connection string.
entityBuilder.ProviderConnectionString = providerString;
// Set the Metadata location.
entityBuilder.Metadata = #"res://*/AdventureWorksModel.csdl|
res://*/AdventureWorksModel.ssdl|
res://*/AdventureWorksModel.msl";
Console.WriteLine(entityBuilder.ToString());
using (EntityConnection conn =
new EntityConnection(entityBuilder.ToString()))
{
conn.Open();
Console.WriteLine("Just testing the connection.");
conn.Close();
}
What i did to make it work.
In the Context file i changed
public MigrateDBFaktura3Entities ()
: base("name=MigrateDBFaktura3Entities")
{
}
to
public MigrateDBFaktura3Entities (string connectionString)
: base(connectionString)
{
}
Then i made a HelperClass
class ConnectionHelper
{
public static string CreateConnectionString(LocationModel LM, string metaData)
{
const string appName = "EntityFramework";
const string providerName = "System.Data.SqlClient";
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.DataSource = LM.datasource;
sqlBuilder.InitialCatalog = LM.catalog;
sqlBuilder.UserID = LM.Username;
sqlBuilder.Password = LM.Password;
sqlBuilder.MultipleActiveResultSets = true;
sqlBuilder.PersistSecurityInfo = true;
sqlBuilder.ApplicationName = appName;
EntityConnectionStringBuilder efBuilder = new EntityConnectionStringBuilder();
efBuilder.Metadata = metaData;
efBuilder.Provider = providerName;
efBuilder.ProviderConnectionString = sqlBuilder.ConnectionString;
var t = efBuilder.ConnectionString;
return efBuilder.ConnectionString;
}
public static FastecData CreateConnection(LocationModel locationmodel, string metaData = "res://*/DB.ServerData.csdl|res://*/DB.ServerData.ssdl|res://*/DB.ServerData.msl")
{
return new FastecData(ConnectionHelper.CreateConnectionString(locationmodel, metaData));
}
}
The LocationModel is Database that purly contains the data for the different servers i will connect to to get data from.
Then when i need to connect to it i only need to
MigrateDBFaktura3Entities db = ConnectionHelper.CreateConnection(CurrentLocation)
where CurrentLocation is a LocationModel

error when trying to programatically build connection string for EF 6

I am using EF ver 6 and I am trying to build my connection string programatically as follows:
public GlContext() : base(ConnectionString()) { }
private static string ConnectionString()
{
SqlConnectionStringBuilder sqlBuilder = new sqlConnectionStringBuilder();
sqlBuilder.DataSource = "myserver";
sqlBuilder.InitialCatalog = "GLPROD";
sqlBuilder.PersistSecurityInfo = true;
sqlBuilder.IntegratedSecurity = false;
sqlBuilder.MultipleActiveResultSets = true;
sqlBuilder.UserID = "user";
sqlBuilder.Password = "pwd";
sqlBuilder.ApplicationName = "EntityFramework";
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.ProviderConnectionString = sqlBuilder.ToString();
entityBuilder.Provider = "System.Data.SqlClient";
return entityBuilder.ToString();
}
When trying to use GlContext I get this error:
keyword not supported: 'provider'
I have spent hours trying to figure out why this code would not work... if I load it from app.config then it works well. Any suggestion is appreciated.
Thanks
EntityConnectionStringBuilder should be used for EDMX model and for Code First model (DbContext based ones) you should use SqlConnectionStringBuilder.

Trying to concatenate database name in connection string

I am trying to concatenate database name in connection string like this:
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
string connectionString = "Server=My-PC\\SQLEXPRESS; Database="+name+";Integrated Security=True; App=EntityFramework;";
FieldInfo connectionStringField = GetType().BaseType.GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
connectionStringField.SetValue(this, connectionString);
}
But it throws exception: login failed for the database.
When I hard code the database name it works:
string connectionString = "Server=My-PC\\SQLEXPRESS;
Database=mydb;Integrated Security=True; App=EntityFramework;";
Anyone please guide me what am doing wrong.
Thanx
EDIT:
I have also tried this:
`string domaniName = Helpers.RouteManager.GetSubDomain();
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder["Data Source"] = "MY-PC\\SQLEXPRESS";
sqlBuilder["Initial Catalog"] = domaniName+"_db";
sqlBuilder["Integrated Security"] = true;
sqlBuilder["Application Name"] = "EntityFramework";`
but still getting the same result. When i hardcode dbname it works fine.
Please guide me.
Thanx.

The type initializer for 'NameSpace.Settings' threw an exception

I've a very simple class that I've added method GetConnectionString(). After adding it whenever any value is accesses from the Settings class it throws an exception The type initializer for 'NameSpace.Settings' threw an exception. As soon as I remove GetConnectionString() program works fine.
using System.Data.EntityClient;
using System.Data.SqlClient;
namespace CRM {
static class Settings {
public static bool userAuthenticated = false;
public static string userGroup = "";
public static Klienci currentlySelectedClient;
public static string sqlDataConnectionDetailsCRM = GetConnectionString();
public static string GetConnectionString() {
string connection = "";
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.InitialCatalog = dbInitialCatalog;
sqlBuilder.DataSource = dbServer;
sqlBuilder.IntegratedSecurity = false;
sqlBuilder.UserID = dbUserName;
sqlBuilder.Password = dbPasswWord;
sqlBuilder.MultipleActiveResultSets = true;
EntityConnectionStringBuilder entity = new EntityConnectionStringBuilder();
entity.Metadata = #"res://*/Data.System.csdl|res://*/Data.System.ssdl|res://*/Data.System.msl";
entity.Provider = "System.Data.SqlClient";
entity.ProviderConnectionString = sqlBuilder.ToString();
connection = entity.ToString();
return connection;
}
}
}
If I comment out sqlBuilder and entity. It works fine..
public static string GetConnectionString() {
string connection = "";
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
//sqlBuilder.InitialCatalog = dbInitialCatalog;
//sqlBuilder.DataSource = dbServer;
//sqlBuilder.IntegratedSecurity = false;
//sqlBuilder.UserID = dbUserName;
//sqlBuilder.Password = dbPasswWord;
//sqlBuilder.MultipleActiveResultSets = true;
EntityConnectionStringBuilder entity = new EntityConnectionStringBuilder();
//entity.Metadata = #"res://*/Data.System.csdl|res://*/Data.System.ssdl|res://*/Data.System.msl";
//entity.Provider = "System.Data.SqlClient";
//entity.ProviderConnectionString = sqlBuilder.ToString();
connection = entity.ToString();
return connection;
}
What's going on? It seems fine to me..
Edit:
InnerException:
exception = "System.ArgumentNullException: Value cannot be
null.\r\nParameter name: Initial Catalog\r\n at
System.Data.SqlClient.SqlConnectionStringBuilder.set_InitialCatalog(String
value)\r\n at CRM.Settings.GetConnectionString() in
C:\Projects\Project.C.S...
While public static string dbInitialCatalog = "BazaCRM"; is set in Settings class.
The order of the fields being initialized is not guaranteed. What's going on here is that the sqlDataConnectionDetailsCRM is being initialized before the dbInitialCatalog field.
If you change those other static fields to be const it should fix it.
Or a better way might be to just removed your public static field, and retrieve the connection string from the method, or you might also like to investigate the Lazy<T> class, and use that to build the connection string the first time it's needed.
According to your error the value of dbInitialCatalog seems to be null, so the connection string builder is throwing an error. Because this is inside the static constructor of a class, the type itself can't be loaded and the whole thing fails.
Have you tried manually supplying the connection string yourself?

Get user and password from ConnectionStringSettings

How can I get the user and password from such a connectionString in the app.config with a .NET function?
Of course I could read that string and get the value after the ID= and Password=.
<connectionStrings>
<add name="MyConString" connectionString="Data Source=(local);Initial Catalog=MyDatabase;Persist Security Info=True;User ID=MyUsername Password=MyPassword;Connect providerName="System.Data.SqlClient"/>
</connectionStrings>
use the ConnectionBuilderClass
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder("Your connection string");
string password = builder.Password;
together with the
string connString = ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString;
to achieve this.
If you need a more generic approach for parsing the connection string (one that doesn't deal with the specifics of one database provider) you can also use
System.Data.Common.DbConnectionStringBuilder
which is a base class for other classes like SqlConnectionStringBuilder etc.
You can create an instance of DbConnectionStringBuilder and in my case I needed to have one configurable connection string that I could get information from -- regardless of the database provider type. A few options if you need this flexibility -- you could create the appropriate ConnectionStringBuilder for your provider as others have suggested -- this would likely be required for most cases where provider-specific properties are needed.
Or if you want to read just a couple generic properties, you could use DbConnectionStringBuilder if you just need the user id and password for example.
This sample should work for ANY connection string that includes user id and password.
DbConnectionStringBuilder db = new DbConnectionStringBuilder();
db.ConnectionString = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
var username = db["User Id"].ToString();
var password = db["Password"].ToString();
SqlConnectionStringBuilder con = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
string myUser = con.UserID;
string myPass = con.Password;
var builder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString)
var user = builder.UserID;
var password = builder.Password;
You can get the connection string from the following
SqlConnectionStringBuilder yourconn = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString);
string password = yourconn.Password;
You can then get the substring you are looking for .
Just to add a bit to Tomas Walek's answer.
This approach would work only if "User ID" in the connection string is capitalized correctly. Oracle provider accepted "User Id" OK, but SqlConnectionStringBuilder did not work.
public static class DbConnectionFactory
{
public static ConnectionStringSettings AppConnectionSettings = ConfigurationManager.ConnectionStrings["{A connection string name}"];
public static SqlConnectionStringBuilder AppConnBuilder = new SqlConnectionStringBuilder(AppConnectionSettings.ConnectionString);
public static string DbUserID
{
get
{
return AppConnBuilder.UserID;
}
set { }
}
}
add a reference to System.Configuration and then use:
using System.Configuration;
string MyDBConnection = ConfigurationManager.ConnectionStrings["MyDBConnection"].ConnectionString;
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(MyDBConnection);
string UserID = builder.UserID;
string Password = builder.Password;
string ServerName = builder.DataSource;
string DatabaseName = builder.InitialCatalog;
public static string GetConnectionSettings(string searchSetting )
{
var con = ConfigurationManager.ConnectionStrings["yourConnectionHere"]‌​.ConnectionString;
String[] myString = con.Split(';');
Dictionary<string, string> dict = new Dictionary<string, string>();
for (int i = 0; i < myString.Count(); i++)
{
String[] con3 = myString[i].Split('='); dict.Add(con3[0], con3[1]);
}
return dict[searchSetting];
}
for searchSetting you can use what you want "User Is" or password.
another way is to use regular expression (which I did), with a more forgiving pattern, to handle different ways a user id could be provided on the connection string:
public static string GetUserIdFromConnectionString(string connectionString)
{
return new Regex("USER\\s+ID\\=\\s*?(?<UserId>\\w+)",
RegexOptions.IgnoreCase)
.Match(connectionString)
.Groups["UserId"]
?.Value;
}
Extension method to get "User Id" from connectionString in DbConnection:
using System;
using System.Data.Common;
using System.Text.RegularExpressions;
namespace DemoProject.Helpers
{
public static class DbConnectionExtensions
{
public static string GetUserId(this DbConnection connection)
{
const string userIdPattern1 = "User[ ]*Id";
const string userIdPattern2 = "UID";
var connectionString = connection.ConnectionString;
foreach (var item in connectionString.Split(';'))
{
var index = item.IndexOf('=');
if (index == -1)
continue;
var property = item.Substring(0, index).Trim();
if (Regex.IsMatch(property, userIdPattern1, RegexOptions.IgnoreCase) ||
Regex.IsMatch(property, userIdPattern2, RegexOptions.IgnoreCase))
{
var userId = item.Substring(index + 1).Trim();
return userId;
}
}
throw new Exception("Couldn't find \"User Id\" in connectionString");
}
}
}
Example #1 of using:
using DemoProject.Helpers;
using Oracle.ManagedDataAccess.Client;
namespace DemoProject
{
class Program
{
static void Main(string[] args)
{
const string connectionString = "Data Source=(DESCRIPTION=" +
"(ADDRESS=(PROTOCOL=TCP)(HOST=oracle19c-vm)(PORT=1521))" +
"(CONNECT_DATA=(SERVICE_NAME=ORCLPDB1)));" +
"User Id=JOHN;" +
"Password=pwd123";
var connection = new OracleConnection(connectionString);
var userId = connection.GetUserId();
}
}
}
Example #2 of using:
using DemoProject.Helpers;
using Npgsql;
namespace DemoProject
{
class Program
{
static void Main(string[] args)
{
const string connectionString = "Server=postgre-vm;" +
"User Id=JOHN;" +
"Password=pwd123;" +
"Database=DEV1";
var connection = new NpgsqlConnection(connectionString);
var userId = connection.GetUserId();
}
}
}
Also you can add the 2nd extension method to get the password
var connString = ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString;
var tokens = connString.Split(';');
string userId;
string password;
for(var i = 0; i < tokens.Length; i++) {
var token = tokens[i];
if(token.StartsWith("User ID"))
userId = token.Substring(token.IndexOf("=") + 1);
if(token.StartsWith("Password"))
password = token.Substring(token.IndexOf("=") + 1);
}
string connectionString = ConfigurationManager.ConnectionStrings["MyConString"].ConnectionString;
var tokens = connectionString.Split(';').Select(n => n.Split('=');
string userId = tokens.First(n => n[0].Equals("User ID").Select(n => n[1]);
string password = tokens.First(n => n[0].Equals("Password").Select(n => n[1]);

Categories