Can't get web.config transform to work - c#

I have an ASP.Net application. I created the transforms for the Web.config file to produce Web.Debug.config and Web.Release.config. Unfortunately, I can't get the code to read these transforms at run time. Here's a snippet of the code that's reading the .config file:
protected void Page_Load(object sender, EventArgs e)
{
Logger logger = LogManager.GetCurrentClassLogger();
string config = ConfigurationManager.AppSettings["Configuration"];
Label1.Text = string.Format("Configuration application string = \"{0}\"", config);
Here is a snippet from the original Web.config file:
<configuration>
<appSettings>
<add key="Configuration" value="Default"/>
</appSettings>
Here's the corresponding snippet from the Web.Release.config file:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings xdt:Transform="Replace">
<add key="Configuration" value="Release"/>
</appSettings>
When I preview the transform, all is good (i.e., I see that the value of "Configuration" is "Release"). However, when I build, publish, and run it, I get the default value.
I read elsewhere that the transforms don't work on the build but rather on the publish, but I'm publishing to C:\inetpub\wwwroot. And when I look at the Web.config file there it does say "Release". Why isn't it showing up when I run my program? (This is Windows 7 Professional and VS2013.)

Related

C# Cannot read from App.config file in MVC

I have an MVC project and am trying to store my API keys in a separate config file which I will ignore when pushing the code to Git. According to MSDN I should be able to store them in an App.config like like so
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="APIKey" value="APIKeyValue" />
</appSettings>
</configuration>
I should then be able to read from the file by creating a method in a model
public class KeyTest
{
public string KeyTestCall()
{
string testkey = ConfigurationManager.AppSettings.Get("APIKey");
return testkey;
}
}
and then invoke the method in my controller to assign the value from my App.config file (just so I know I'm getting the value).
public void Testing()
{
KeyTest k = new KeyTest();
ViewBag.x = k;
}
At no point will the code break for a breakpoint, the build will succeed and I can't tell if I'm getting the value or not. Any help is much appreciated. Thanks!
For a web application such as an MVC app, it's a Web.config file, not an App.config
In addition to above (re: web.config vs app.config) if you want to remove "secrets" from source control, this is one way to do it:
In web.config
<?xml version="1.0" encoding="utf-8"?>
<cofiguration>
....
<appSettings file="AppKeys.config">
<add key="SomeOtherSettingThatHasNoSecrets" value="foo" />
...
Then in a separte AppKeys.config file (you can name this whatever.config, sample as named in the above), that you don't add to Git/source control:
<appSettings>
<add key="SomeSecretKey" value="the secret" />
...
Note that AppKeys.config doesn't have an XML declaration.
Hth.

Modify appSettings in the custom config file which is referenced via 'file' attribute

In appSettings section of Web.config a file attribute is used referencing a custom config file. The goal is to have possibility to modify some app-settings in the custom config without causing the application to be restarted.
Web.config
<appSettings file="CustomAppSettings.config">
<add key="key1" value="val2" />
</appSettings>
CustomAppSettings.config
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<add key="customKey1" value="custVal2"/>
</appSettings>
The following code does not work. It saves the value to Web.config but expected is to save it to the CustomAppSettings.config because so it will not restart the application (Source).
var configuration = WebConfigurationManager.OpenWebConfiguration("~/");
configuration.AppSettings.Settings[key].Value = value.ToString();
configuration.Save();
This does not work as well.
var configuration = WebConfigurationManager.OpenWebConfiguration("~/CustomAppSettings.config");
What am I doing wrong? Could someone point me to the right direction?
use configSource instead of file.
<appSettings configSource="CustomAppSettings.config" />
use ConfigurationSaveMode.Minimal on saving.
var configuration = WebConfigurationManager.OpenWebConfiguration("~/");
configuration.AppSettings.Settings[key].Value = value.ToString();
configuration.Save(ConfigurationSaveMode.Minimal);

Reading connection string from external config file

I have created a console application and an app.config file and Connections.config file.
The app.config file has a connectionstring property source pointing to the Connections.config
When I tried to read the connection string in the application, I get a ConfigurationErrorException
This is my main method.
static void Main(string[] args)
{
var settings = ConfigurationManager.ConnectionStrings;
if (settings != null)
{
foreach (ConnectionStringSettings setting in settings)
{
Console.WriteLine(setting.ConnectionString);
}
}
}
App.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings configSource="Connections.config"></connectionStrings>
</configuration>
Connections.config file
<?xml version="1.0" encoding="utf-8" ?>
<connectionStrings>
<add name="SQLDBConnecion"
providerName="System.Data.ProviderName"
connectionString="" />
</connectionStrings>
Here I observed two things.
First: If I specify configSource I am unable to read the connection string (throwing exception.)
Second: If I put same connection string in App.config file and tried to read then the code is working but getting two connection string (which supposed to be return only one which is empty string)
The first connection string is sqlexpress connection string like this
data source=.\SQLEXPRESS;Integrated Security=SSPI;
AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true
second connection string it returning is empty string (This is expected).
I want to read connection string from external file like in my scenario. How to do that? What am I missing here?
MSDN says:
Do not include any additional elements, sections, or attributes.
You need to remove the XML encoding.
Edit
Also, you need to set the properties of your config file to Copy to Output Directory = Copy if newer or Copy always.
Edit 2
To build on what Dave said, you add the clear element to your external file. Your final Connections.config file should look exactly like this:
<connectionStrings>
<clear/>
<add name="Name"
providerName="System.Data.ProviderName"
connectionString="Valid Connection String;" />
</connectionStrings>
Your Connections.config file should be as shown below without the xml header
<connectionStrings>
<add name="SQLDBConnecion"
providerName="System.Data.ProviderName"
connectionString="" />
</connectionStrings>
Also for it to correctly locate the file in your console application, please set the Copy to Output Directory to Copy Always or Copy If Newer.
That first connection string you are getting is inherited from the machine.config. This is described in the MSDN documentation. http://msdn.microsoft.com/en-us/library/bf7sd233(v=vs.90).aspx
You can use the Clear tag in your config file to remove inherited connection strings.
http://msdn.microsoft.com/en-us/library/ayb15wz8(v=vs.90).aspx
<connectionStrings>
<clear/>
<add name="SQLDBConnecion"
providerName="System.Data.ProviderName"
connectionString="" />
</connectionStrings>
There is a nice article on MSDN: https://msdn.microsoft.com/en-us/library/ms254494(v=vs.110).aspx.
Quote from the article:
To store connection strings in an external configuration file, create
a separate file that contains only the connectionStrings section. Do
not include any additional elements, sections, or attributes. This
example shows the syntax for an external configuration file.
<connectionStrings>
<add name="Name"
providerName="System.Data.ProviderName"
connectionString="Valid Connection String;" />
</connectionStrings>
Hope this helps people who run into this question later.

Getting a ConnectionString from app.config

I have a Web project which calls a library project (DataAccess) to retrieve some data from the database. I added an App.config file (Add -> New Item -> Application Configuration File) to the DataAccess project and added a connectionString section like this:
<configuration>
<connectionStrings>
<add name="local"
connectionString="Data Source=.\sql2008;Initial Catalog=myDB;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
In the DataAccess project, I have the BuildConnection method:
internal static SqlConnection BuildConnection()
{
string connectionString = ConfigurationManager.ConnectionStrings["local"].ToString();
return new SqlConnection(connectionString);
}
When I call the method from the Web project, it throws a null exception complaining that the "local" connection string doesn't exist. After debugging it for a while I added the same connection string to the Web.config of the Web project, and now it works fine. The problem though is that I want to isolate the DataAccess project from the Web project, in other words, I want the DataAccess project to use its own app.config file no matter who calls it. Is this even possible? Any help would be appreciated.
at runtime, there is just one config file. so the config file of the active project is only
considered. also, you cannot have a class library project as an active/startup project i.e.
say you have 4 Projects in your solution, and each of them has a config file, then when you run the application, only the active project's(the one which is your startup project) config file is recognized.
Now what can you do?
if you just want to isolate the sections of the config file, then you can have config file in each of your Projects, which in turn, are referenced in the main projects config i.e.
Web.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings file="YourSettings.config">
<add key="KeyToOverride" value="Original" />
<add key="KeyToNotOverride" value="Standard" />
</appSettings>
<system.web>
<!-- standard web settings go here -->
</system.web>
YourSettings.config:
<appSettings>
<add key="KeyToOverride" value="Overridden" />
<add key="KeyToBeAdded" value="EntirelyNew" />
</appSettings>
read more about it here
if you want to have separate config files for your active project itself, than that's whole different story altogether.
its kind of ugly tweak, but read about it here
An app.config is used when you use in an Application. For a library project using a app config file not helps. Even you put it reference library the code will be in web server.
So this type isolation has no sense for any security issue.
But approach of putting things to the right place you are right, the problem is when you reference a dll it doesn't include the dll project's config.
If you want more :) Just read app.config in your lib project and using a code generator create a connection string object such as public static string ConnectionString = $GeneratedCode$;
Yes, it's possible.
Your app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="foo" value="bar"/>
</appSettings>
</configuration>
Your DataAccess layer:
namespace MyApp.DataAccess
{
public class DB
{
public string cfg;
public DB()
{
var asmName = System.Reflection.Assembly.GetAssembly(this.GetType()).GetName().Name;
var asmPath = System.Web.HttpContext.Current.Server.MapPath(#"bin\" + asmName + ".dll");
var cm = ConfigurationManager.OpenExeConfiguration(asmPath);
this.cfg = cm.AppSettings.Settings["foo"].Value;
}
}
}
Here's how to use it:
namespace MyApp.WebApp
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var db = new MyApp.DataAccess.DB();
Response.Write(db.cfg);
}
}
}
When you compile data access project, it'll generate a MyApp.DataAccess.dll.config out of your app.config content. Add MyApp.DataAccess.dll.config and MyApp.DataAccess.dll to your web app project and make sure to mark Copy To Output Directory to Copy if newer for MyApp.DataAccess.dll.config.

Best practice to include log4Net external config file in ASP.NET

I have seen at least two ways to include an external log4net config file in an ASP.NET web application:
Having the following attribute in your AssemblyInfo.cs file:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log.config", Watch = true)]
Calling the XmlConfigurator in the Global.asax.cs:
protected void Application_Start()
{
XmlConfigurator.Configure(new FileInfo("Log.config"));
}
What would be the best practice to do it?
At startup, call:
XmlConfigurator.Configure();
In your Web.config, specify log4net.Config in appSettings:
<add key="log4net.Config" value="Log.config" />
This special setting allows you to change the log configuration without having to recompile. Especially helpful for moving between multiple environments.
Example
Consider the following project file structure:
\config\log4net\debug.config
\config\log4net\staging.config
\config\log4net\release.config
\config\appSettings\debug.config
\config\appSettings\staging.config
\config\appSettings\release.config
Application and logging configurations are distinguished for each environment. References to the logging configurations are maintained in the application settings.
\config\appSettings\debug.config:
<appSettings>
<add key="log4net.Config" value="config\log4net\debug.config" />
...
</appSettings>
\config\appSettings\staging.config:
<appSettings>
<add key="log4net.Config" value="config\log4net\staging.config" />
...
</appSettings>
\config\appSettings\release.config:
<appSettings>
<add key="log4net.Config" value="config\log4net\release.config" />
...
</appSettings>
Changing environments is a simple matter of updating the appSettings file in Web.config.
<appSettings file="config\appSettings\staging.config">
...
</appSettings>
I was dissatisfied with the "magic" configuration approach, because I wanted to specify my configuration in a path with an environment variable (%PUBLIC%\MyApp\MySettings.config).
So instead, I have this in my app.config:
<add key="MyLog4NetConfigFile" value="%PUBLIC%\MyApp\MySettings.config"/>
And do this to set my log4net configuration:
var configFile = ConfigurationManager.AppSettings.Get("MyLog4NetConfigFile");
if( !string.IsNullOrEmpty(configFile))
{
configFile = Environment.ExpandEnvironmentVariables(configFile);
XmlConfigurator.Configure(new FileInfo(configFile));
}

Categories