Dynamic use of multiple config files in C# application - c#

I've done a lot of research on this, and tried a number of approaches, but I'm beginning to think that what I want to do can't be done. To wit -- I am building an application that will be used by multiple clients. Each client will have their own database connection requirements, and their own set of customizations to control some of the behaviour of the application.
What I want to do is to create a .config file for each individual client, then use a command-line argument that will specify which .config file to load. Each config file will have its own section, and its own . I've gone through much of the documentation con ConfigurationManager and the Configuration classes and tried a number of different approaches, all of which have failed.
The basic question is "when I open a .config file, how do I tell the application to make this .config the default configuration?" For example, when I later make reference to a value in appSettings, or a database connection string, how do make sure that these references will each map to the custom configuration I have loaded, and not the one created by default by Visual Studio?
I have found all kinds of references to loading configuration files, but nothing that tells me how to dynamically replace the standard one with the one I just loaded. I keep ending up with null reference exceptions and running headlong into brick walls.

You can have multiple connection strings defined in your config file, then refer to them by name.
Example:
<configuration>
<connectionStrings>
<add name="client1Connection"
connectionString="Data Source=(local);Initial Catalog=dbclient1;Integrated Security=True"
providerName="System.Data.SqlClient" />
<add name="client2connection"
connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=dbclient2;Integrated Security=True"
providerName="System.Data.SqlClient" />
...
</connectionStrings>
</configuration>
You can refer to them in you c# code by:
string client1ConnStr = System.Configuration.ConfigurationManager.ConnectionStrings["client1Connection"].ConnectionString;
string client2ConnStr = System.Configuration.ConfigurationManager.ConnectionStrings["client2connection"].ConnectionString;

Related

I have two web.config files. Which one should I use?

I recently built an application using visual studio express. This application was built using a local DB provided by VS express. I now have a subscription (free trial) to Microsoft Azure. What changes do I need to make to my project in order to point my project to the newly created Azure DB?
I also noticed I have 2 web.config files. one in the root directory and one in the views folder.
I believe I have to make an update to my connection string, but in a specific config file or both?
Here is my root directory web.config connection string:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source= LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-MvcMovie-20160922101748.mdf;Initial Catalog=aspnet-MvcMovie-20160922101748;Integrated Security=True"
providerName="System.Data.SqlClient" />
<add name="MovieDBContext" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True" providerName="System.Data.SqlClient"/>
and my (views) web.config connection string:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-MvcMovie-20130603030321.mdf;Initial Catalog=aspnet-MvcMovie-20130603030321;Integrated Security=True" providerName="System.Data.SqlClient" />
<add name="MovieDBContext" connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True"
providerName="System.Data.SqlClient"/>
Any help would be highly appreciated.
I believe only one web.config with connection strings should be enough. Keep the one in the root.
Download Azure DB connection strings from the Azure portal and replace connectionString values in the web.config file with the Azure DB connection string(s).
You might also need to whitelist your machine's IP address in the Azure Portal to allow connections to Azure DB.
You only need to change the web.config on the root folder as thats the one used by the application.
And you are right, you need to point the connection string to your Azure database.
You definitely only need to update the one web.config in the root of the application with the connection string. The other web.config in the views folder is needed for your views to use html helpers and to make routing work as you expect in an mvc application so do not remove it.

Using web.config connection string in data access project

I'm on .NET 4.6.1, Visual Studio 2015, SQL Server Developer 2016. I want to specify my EF connection string in my main project's web.config, but I cannot for the life of me figure out how to reference that in my data access project. Every answer I can find says to do the same as in this one--that is, use this:
System.Configuration.ConfigurationManager
.ConnectionStrings["connectionStringName"].ConnectionString;
When I use that, however, the valid connection string isn't being passed. It's instead getting one that appears to be the default; the data source is being set to .\SQLEXPRESS when I have no string with that defined anywhere. Searching all files in the solution for SQLEXPRESS returns no results, so it's not hardcoded anywhere.
What is the correct way to pass my connection string from my main web.config (with the relevant transforms per build) to my data access project?
There is only one app.config / web.config that will be read from at run time and that is the config associated with the applications entry point. So if you have a web project and a referenced project that serves at the data access layer and you want to read a connection string from the config the web.config of the web project is used. The same is true for a windows application or wpf etc, only the applications main entry point's configuration will be used. Once your application is running you can reference that app.config / web.config from anywhere in your code though as you generally do this using string identifiers.
In other words if you have a project with your Data Access compiled to MyDA.dll and you app.config in that project that might be output to MyDA.dll.config (this does not happen by default) anything you have in MyDA.dll.config is ignored at runtime. The file will not be read from, only the web.config will be used OR the app.config of the .exe's entry point.
For Entity Framework's DbContext you can pass the name of the connection string directly to the constructor. You do not have to retrieve the connection string and pass it yourself. So give each connection a specific unique name in your web.config.
<connectionStrings>
<add name="ConnectionName1" connectionString="Data Source=(local);Database=YourDB;User Id=YourUser;Password=yourPassword" providerName="System.Data.SqlClient" />
<add name="ConnectionName2" connectionString="Data Source=(local);Database=YourDB2;User Id=YourUser2;Password=yourPassword2" providerName="System.Data.SqlClient" />
<!-- more here -->
</connectionStrings>
Then in your code you can create your Entity Framework's DbContext using that name.
var myEntities = new MyEntities("ConnectionName1"); // MyEntities is some class that derives from DbContext
In my past projects the DbContext I work with usually always maps to one database at run time. What I mean here is I would not use the same DbContext type multiple times pointing to different databases. In this case I hard code that name right into my DbContext type and make sure that my consuming applications have that connection name listed in the web.config or app.config respectively.
public class MyEntities : DbContext {
public MyEntities() : base("ConnectionName1") {}
}
// calling code now never has to know about the connection
using(var myEntities = new MyEntities()) { /* do something here */}
Alternatively if you really do want the complete connection element you can reference System.Configuration (add it to your project references in the project where you make the following call) and call it this way.
var connection = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionName1"];
var conString = connection.ConnectionString; // you can also get the provider
var myEntities = new MyEntities(conString);
I have not used this approach in a while but maybe there is a good reason to use it in your case.
The data source is being set to .\SQLEXPRESS when I have no string with that defined anywhere. Searching all files in the solution for SQLEXPRESS returns no results, so it's not hardcoded anywhere.
Its hardcoded in your machine config file. Simply add:
<clear />
Above your first connection string to remove it.
You could remove the .\SQLExpress connection string from line 126 in the machine.config, however IMHO play on the safe side and dont mess with machine config, preferring to use <clear /> instead.
Have you tried connection to the Server Explorer -> Data Connections and having the property auto generated? Next thing I would tried is adding an ADO.Net data model and pointing to the correct DB with the Access driver. It may be as simple as provider on the configuration string.
Here is a simplified example and/or proper way given by MSDN:
var connectionString = ConfigurationManager.ConnectionStrings["connectionStringName"].ConnectionString;
config file like the following:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<connectionStrings>
<add name="connectionStringName" connectionString="Data Source=(LocalDB)\v11.0;Initial Catalog=DatabaseName;Integrated Security=True;Pooling=False" />
</connectionStrings>
</configuration>
Needed namespaces:
System.Configuration
From : https://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.connectionstrings(v=vs.110).aspx
As far as I remember, when using EF, it creates a connection string that matches the name of the context you defined, so, if your context is named MyContext then you should define a connection string with that name in your app/web.config. To save you the trouble of writing the EF connection string on your own (which is much longer than a regular ADO.Net connection string), just copy the one that was generate in the DLLs .config file.
Once you have that, you can use the configuration transformation functionality built into web projects, that allows you to change portions of the .config file depending on the current build configuration, for example:
web.config - Will hold the DEVELOPMENT connection string.
web.staging.config - will hold a replace transformation with the STAGING connection string.
web.release.config - will hold a replace transformation with the RELEASE connection string.
Hope it helps!
<configuration>
<connectionStrings>
<add name="CONNECTIONSTRINGNAME" connectionString="server=.; Database=YOURDATABASENAME;Integrated Security=true;" providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>
change the capital letters with your own data

Trying to replace connectionStrings element for continous deployment in Visual Studio Team Services

I am using Visual Studio Team Services, previously Visual Studio Online, to continuously deploy my web app. I have tried setting up the web.config transformation, I believe it is working after I have changed the configurations setting to Release | Any CPU as instructed here Web config transforms not working with Visual Studio online, VS2013 and Azure .
The issue I believe I am having is more with the transform its self.
Right now I have the following in my web.config
<connectionStrings configSource="connections.config"/>
I want this so I can avoid checking in connections.config and still have my db connections setup locally. What I want to do is replace the above line of code with something like this.
<connectionStrings>
<add name="umbracoDB" connectionString="blah " providerName="System.Data.SqlClient" />
<add name="EFdb" connectionString="blah" providerName="System.Data.EntityClient" />
</connectionStrings>
I am using
<connectionStrings configSource="connections.config" xdt:Transform="Remove" xdt:Locator="Match(configSource)"/>
and it seems to be successfully removing the configSource connectionStrings element. But I am still confused on how to add back my replacement connectionStrings and add elements?
Devin
One thing that you can do is to store your DB connection strings as secret variables in Build/Release and then use the Tokenizer task from Marketplace
to replace the connection string token with actual string.
Tokenizer task has support for the environments in Release Management.
If you want to replace your connectionStrings element during deployment, try usign the Replace transform:
<connectionStrings xdt:Transform="Replace">
<add name="umbracoDB" connectionString="blah " providerName="System.Data.SqlClient" />
<add name="EFdb" connectionString="blah" providerName="System.Data.EntityClient" />
</connectionStrings>

Connection string in C# for a local db in a desktop application

I'm trying to use a local db for my application, and want it to reside in a folder inside my application. Unlees I'm missing something, this shouldn't be a problem with user rights, since it is in the application folder.
The connection string is this:
<connectionStrings>
<add name="Calendario2DB"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=\AppData\Database1.mdf;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
I'm Using a code first aproach, so the database should be generated (filled) at run time, but I have a problem with
AttachDbFilename=\AppData\Database1.mdf
This should be pointing to a folder in my app (called appdata) but is not working with an error:
A file activation error occurred. The physical file name '\AppData\Database1.mdf' may be incorrect. Diagnose and correct additional errors, and retry the operation.
CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
So how do I have to write the path name to the phisical file?
You should use the built in |DataDirectory| feature.
<connectionStrings>
<add name="Calendario2DB"
connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Database1.mdf;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
Then the database would be located in:
\Program Files\Application Location\App_Data\Database1.mdf
According to the documentation you cannot use relative paths without using |DataDirectory|:
The path may be absolute or relative by using the DataDirectory substitution string. If DataDirectory is used, the database file must exist within a subdirectory of the directory pointed to by the substitution string.

Unable to retrieve metadata - MVC application

I was following this to create a simple MVC application. After creating the model, when I tried to add controller, I got the following error :
Unable to retrieve metadata for "MvcApplication.Models.Movie". Invalid value for key "attachdbfilename".
Can someone tell why I am getting this error.
Update : I saw this wherein solution is provided by changing the providerName. But in my case it is already System.Data.SqlClient. Following are my connectionStrings :
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=aspnet-MvcApplication-20130708120940;Integrated Security=SSPI" providerName="System.Data.SqlClient" />
<add name="MovieDBContext" connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\Movies.mdf;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
The error message is saying invalid value for AttachDbFilename which is part of your MovieDbContext connection string.
The connection string currently shows this AttachDbFilename=|DataDirectory|\Movies.mdf so it appears the mdf file is now missing from the App_Data folder.
I found the solution. the problem is the "|DataDirectory|". I Changed "|" to "\"
I just solved this problem. Even though I am new to MVC, I am bit embarrassed to say, I was trying a work around for another problem I was having and moved my SetInitializer into my classname : DbContext class.
The app worked just fine and the database was created fine as I changed the models but I couldn't add new controllers or modify current controllers using the scaffolding tool.
I began receiving errors. One of them is listed above and another is:
Unable to retrieve meta data for 'namespace.Models.class'. A file
activation error occurred. The physical file name '\name.mdf'
may be incorrect. Diagnose and correct additional errors, and retry the
operation.
CREATE DATABASE failed. Some file names listed could not be created.
Check related errors.
Moving the SetInitializer back into my Global.asax fixed the problem.

Categories