I've an application which insert/save data in different databases hosted on different server. UI may be different but at the end data which is getting saved is almost same.
So i want to use the same DataAccessLayer but want to change the connectionString based on the loggedin user.
Dependency can be configured in startup.cs but at that time i may not know the DataBase user would like to work with.
on login page i'm asking user to select the database to work with, so only way to change the connection string is after login page.
Any suggestion?
public class ConnectionRepository : IConnectionRepository
{
private IDbConnection _cnn = null;
public IDbConnection GetOpenConnection(string databaseName)
{
if (_cnn != null && _cnn.ConnectionString.ToLower().Contains(databaseName.ToLower()))
{
_cnn.Open();
return _cnn;
}
var cnn = ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString();
//Now replace database name in connection string with whichever one supplied
var cb = new SqlConnectionStringBuilder(cnn) { InitialCatalog = databaseName };
// wrap the connection with a profiling connection that tracks timings
return new ProfiledDbConnection(new SqlConnection(cb.ConnectionString), MiniProfiler.Current);
}
}
This code replaces the InitialCatalog (database name) part of the connection string dynamically base on the supplied name. The current name is stored in session when the user logs in.
Hope this helps.
Related
I have developed an accounting program that is working beautifully, but now a new need has arisen.
When I enter the program, by default it reads the DB that I put in the file WinSCM.exe.config and if I want to change I have to exit the program and edit the file changing the DB name.
I did not want it to be this way, because my client does accounting for several companies and each company is a DB, so I wanted a way to select a company and when selecting this company the database is automatically changed in the release version.
I'm using Entity Framework to connect to Sql Server DB
Can someone help me?
I'm not sure what reading your DB is, but normally when you use Entity Framework you create a DbContext object whenever you need to do a query, or at utmost a few queries. You are not supposed to keep this DbContext alive for longer periods of time, say more than a few seconds. A minute would be very rare.
Whenever you create the Dbcontext instance you could use the default constructor that uses the config file to get the connection string to the database.
However one of the other constructors let you define the connection string to the database in the constructor. So if you want to construct your DbContext and connect it to a different database, just use that constructor
If you don't know the connection string, but you have a DbConnection to the database, there will be even a constructor for this case.
Hi Everybody Thank alot for your Answer. I just Solved My Question like this:
Fisrt of all, I created a class wich I called ConnetionTolls with this Content://.
public static class ConnectionTools
{
// all params are optional
public static void ChangeDatabase(
this DbContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "")
/* this would be used if the
* connectionString name varied from
* the base EF class name */
{
try
{
// use the const name if it's not null, otherwise
// using the convention of connection string = EF contextname
// grab the type name and we're done
var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
? source.GetType().Name
: configConnectionStringName;
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
// init the sqlbuilder with the full EF connectionstring cargo
var sqlCnxStringBuilder = new SqlConnectionStringBuilder
(entityCnxStringBuilder.ProviderConnectionString);
// only populate parameters with values if added
if (!string.IsNullOrEmpty(initialCatalog))
sqlCnxStringBuilder.InitialCatalog = initialCatalog;
if (!string.IsNullOrEmpty(dataSource))
sqlCnxStringBuilder.DataSource = dataSource;
if (!string.IsNullOrEmpty(userId))
sqlCnxStringBuilder.UserID = userId;
if (!string.IsNullOrEmpty(password))
sqlCnxStringBuilder.Password = password;
// set the integrated security status
sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;
// now flip the properties that were changed
source.Database.Connection.ConnectionString
= sqlCnxStringBuilder.ConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
********the way to use it is like this***************
//I use this method in a diferent Class
//This method returns the Entity i use with new connections
public static MyEntities SelectDb(String DataBase,String sqlUser,String pw, String serverInstance){
var selectedDbase = new MyEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDbase.ChangeDatabase
(
initialCatalog: DataBase,
userId: sqlUser,
password: pw,
dataSource: serverInstance// could be ip address 100.23.45.67 etc
);
return selectedDbase;
}
I want to thank everyone here and on other forums because this was the result of Your Contributions
I have a problem, so I thought I would come to the brightest minds on the web.
I have written an ASP.NET MVC application that interfaces with a web service provided by another application. My app basically just adds some features to the other web application.
Both applications have a database. I am trying to limit the configuration for my application by using the other applications SQL Server credentials. This is so that if they decide to change the password for the other application, mine will just start working.
These credentials are saved in a .DSN file that my application can reach. How can I get my application, which uses Entity Framework, to use a connection string that is created from the details read in the .DSN file?
I can figure out the code to read the .DSN file, so if you wish to provide some code examples you can base them around setting the connection string for EF.
I am also open to other solutions, or even reasons why I shouldn't do this.
Thanks in advance.
PS. As I was writing this, I came up with a little concept. I am going to test it out now to see how it goes. But here is the basics:
On start up, read the needed details into static properties.
public MyContext() : base(getConnectionString()) { }
3.
private SomeObjectTypeHere getConnectionString()
{
//read static properties
//return .....something..... not sure yet....
}
Thoughts on that maybe?
EDIT
I have created a method that reads the .DSN file and gets the server, the user id and the password. I now have these stored in static properties. In my context, how can I set my connection string now that i have the required details.
So, the biggest issue that I was really having was how to set my connection string in Entity Framework. But I was also hoping that maybe someone else had worked with .DSN files.
Anyway, here was my solution. Still looking for problems that might arise from this, so if you can see any issues, let me know!
First, I created a method that was run on startup. This method ran through the .DSN file and picked out the gems.
Keep in mind that I have never worked with .DSN files, and the section that gets the password is unique to my situation.
var DSNFileContents = File.ReadAllLines(WebConfigurationManager.AppSettings["AppPath"] + #"\App.DSN");//reads DSN into a string array
//get UID
string uid = DSNFileContents.Where(line => line.StartsWith("UID")).First().Substring(4);//get UID from array
//test if uid has quotes around it
if (uid[0] == '"' && uid[uid.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
uid = uid.Substring(1, uid.Length - 2);
}
//get server
string server = DSNFileContents.Where(line => line.StartsWith("SERVER")).First().Substring(7);//get the server from the array
//test if server has quotes around it
if (server[0] == '"' && server[server.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
server = server.Substring(1, server.Length - 2);
}
//THIS WON'T WORK 100% FOR ANYONE ELSE. WILL NEED TO BE ADAPTED
//test if PWD is encoded
string password = "";
if (DSNFileContents.Where(line => line.StartsWith("PWD")).First().StartsWith("PWD=/Crypto:"))
{
string secretkey = "<secret>";
string IV = "<alsoSecret>";
byte[] encoded = Convert.FromBase64String(DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(12));
//THIS LINE IN PARTICULAR WILL NOT WORK AS DecodeSQLPassword is a private method I wrote to break the other applications encryption
password = DecodeSQLPassword(encoded, secretkey, IV);
}
else
{
//password was not encrypted
password = DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(4);
}
//build connection string
SqlConnectionStringBuilder cString = new SqlConnectionStringBuilder();
cString.UserID = uid;
cString.Password = password;
cString.InitialCatalog = "mydatabase";
cString.DataSource = server;
cString.ConnectTimeout = 30;
//statProps is a static class that I have created to hold some variables that are used globally so that I don't have to I/O too much.
statProps.ConnectionString = cString.ConnectionString;
Now that I have the connection string saved, I just have my database Context use it as below,
public class myContext : DbContext
{
public myContext() : base(statProps.ConnectionString) { }
//all my DbSets e.g.
public DbSet<Person> Persons{ get; set; }
}
This is simple, yes, but I hoping that it can provide some information to anyone that was looking to do something similar but was not sure about how it should be handled.
Again, let me know if you like or dislike this solution and if you dislike it, what is your solution and why.
Thanks again!
I have my entity model and connection set up, and as you probably know when you set up the connection to be stored in the config file, it recommends you don't store the "sensitive" data (i.e. user name and password) in the config file, well what I wanted to do was allow the user to enter that information themselves.
How do I assign it to the connection in code?
Do I have to pull the string, modify it (by adding the user/pass) and then reassign the connection string?
sounds like a desktop (not a web app), correct? since you are probably not running over the internet but rather in a local network why don't you use integrated (windows) security instead of the sql server security and hot have to store the login/password at all.
public class MyContext : DbContext
{
// Add a constructor that takes a connection string
public MyContext(string connString)
: base(connString)
{
}
}
// Call this method from a page or controller
public void ConnectToTheDatabase(string username, string password)
{
// create the connection string; I like to user the builder
System.Data.Common.DbConnectionStringBuilder builder
= new System.Data.Common.DbConnectionStringBuilder();
builder.Add("Server", "tcp:asdfewsdfgwe.database.windows.net,1422");
builder.Add("Database", "supersonic_db");
builder.Add("User ID", username);
builder.Add("Password", password);
builder.Add("Trusted_Connection", "False");
builder.Add("Encrypt", "True");
builder.Add("Connection Timeout", "30");
var connString = builder.ToString();
// Set the connection string
MyContext context = new MyContext(connString);
// Test with something simple
context.Database.Connection.Open();
string version = context.Database.Connection.ServerVersion;
version = version.ToUpper();
}
I have an EF5 ASP.NET MVC 3 (Razor) web site, running under IIS7. Now I want to be able to change the connection string to the MSSQL database depending on the subdomain of the URL, e.g. foo.mydomain.com should connect to my "Foo" database, and bar.mydomain.com should connect to the "Bar" database.
Obviously the DNS records are set up so that they all point to the same web site.
What's the most efficient way of achieving this?
why don't you start passing your own SqlConnection to your YourDbContext?
var partialConString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString;
var connection = new SqlConnection("Initial Catalog=" + Request.Url.Host + ";" + partialConString);
var context = new MyDbContext(connection, true);
You can also change database in the DBContext:
context.Database.Connection.ChangeDatabase("newDbname");
It's not very easy...
You should change the constructor of object context to dynamically change the connection string.
Take the subdomain name using System.Web.HttpContext.Current.Request.Url.Host. Then use it to compute the proper connection string.
You should do this in the designer generated code. Of course this is not a good place.. to make it work use the T4 templating. Open your model and right click on the blank designer surface, then select "Add code generation item" -> Ado.net entity object generation. This will create a .tt file. Open it and look for the constructor syntax. Add your logic there.
Good luck!
I've come up with what I feel is a better solution than all those proposed to date. I'm using the default EntityModelCodeGenerator, so perhaps there are other, better, solutions for other templates - but this works for me:
Create the other half of the partial class MyEntities.
Override OnContextCreated(), which is called from within the class constructor.
Change the store connection string using a regex.
This comes out as follows:
partial void OnContextCreated()
{
// change connection string, depending on subdomain
if (HttpContext.Current == null) return;
var host = HttpContext.Current.Request.Url.Host;
var subdomain = host.Split('.')[0];
switch (subdomain)
{
case "foo":
ChangeDB("Foo");
break;
case "bar":
ChangeDB("Bar");
break;
}
}
private void ChangeDB(string dbName)
{
var ec = Connection as EntityConnection;
if (ec == null) return;
var match = Regex.Match(ec.StoreConnection.ConnectionString, #"Initial Catalog\s*=.*?;", RegexOptions.IgnoreCase);
if (!match.Success) return;
var newDbString = "initial catalog={0};".Fmt(dbName);
ec.StoreConnection.ConnectionString = ec.StoreConnection.ConnectionString.Replace(match.Value, newDbString);
}
Either use different connection strings in the web.config. Maybe research a bit if you can have conditional XSL transformations, that way, when you publish on a specific configuration the web.Release.config will change your Web.Config to be what you need it to be.
Or, use |DataDirectory| string substitution - http://msdn.microsoft.com/en-us/library/cc716756.aspx
more on DataDirectory string substitution here:
http://forums.asp.net/t/1835930.aspx/1?Problem+With+Database+Connection
I guess, if you want to be by the book, create build configurations for each of your separate releases and put the connection string in the respective web..config and when you publish, that XSL transformation will put the connection string in the resulting web.config and voila.
I've done something like that recently by adding some custom configuration, which uses the host header to determine the connectionStringName, which has to be used.
EF5 has a constructor, which can handle this name
var context = new MyDbContex("name=<DBConnectionStringName>");
I just did for a project
public partial class admpDBcontext : DbContext
{
public static string name
{
get
{
if (System.Web.HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority).ToString() == "http://fcoutl.vogmtl.com")
{
return "name=admpDBcontext";
}
else { return "name=admpNyDBcontext"; }
}
}
public admpDBcontext()
: base(name)
{
}
}
And in the web.config I add the connectionString.
I am using Winforms, MySQL and C# in my project. In that I use a connection string in the app settings.
At each new page I will declare a connection string as public and use this string in the connection.
MySqlConnection connection = new MySqlConnection(MyConString);
I want to declare this MyConString only one time in the whole application. How to do this? Where to do?
I don't think you should expose your connection string to your Forms, they don't need to know that. You can encapsulate the creation of connections with a simple factory.
public class ConnectionFactory
{
public static MySqlConnection Create()
{
string connectionString = ConfigurationManager.AppSettings["..."];
MySqlConnection conection = new MySqlConnection(Config.ConnectionStr);
connection.Open();
return connection;
}
}
Then when you need a connection in a Form you can do:
private void button1_click(object sender, EventArg args)
{
using ( var connection = ConnectionFactory.Create() )
{
connection.Execute("...");
}
}
You can try something like the following:
public static class Config
{
public static string ConnectionStr = ConfigurationManager.AppSettings["..."];
}
You can then use it in your code
MySqlConnection connection = new MySqlConnection(Config.ConnectionStr);
Enterpise Library from Microsoft have great DataAccess part which beside other prtoblem solving and this one
You may have a separate class to handle databases and add the connection string as a field there. Each time you want to connect to the database, you may use that class. Also if you may use a property to access the string outside the class if you require.
Hope this helps...
The suggested approach is available at an MSDN article titled Storing and Retrieving Connection Strings. The following samples are slightly modified from this article.
After storing your connection string in an app.config file, you can retrieve all connection strings like so:
static void GetConnectionStrings()
{
var settings = ConfigurationManager.ConnectionStrings;
if (settings != null) {
foreach(ConnectionStringSettings cs in settings) {
Console.WriteLine(cs.Name);
Console.WriteLine(cs.ProviderName);
Console.WriteLine(cs.ConnectionString);
}
}
}
You could alternatively get the connection string by name:
// Returns null if the name is not found.
static string GetConnectionStringByName(string name)
{
string returnValue = null; // Assume failure.
var settings = ConfigurationManager.ConnectionStrings[name];
if (settings != null) {
returnValue = settings.ConnectionString;
}
return returnValue;
}
This also gives you the ability of Securing Connection Strings so that your database username & password are not embedded into your application assembly in clear-text.