Switch different app.config - c#

I have a windows console application. I get some values from app.config. There are for writing log files. When debug, I want to write them on my desktop. But when publish the application, the logs should be in the remote server. Now I have to manually set the values each time between debugging and publish.
Can we create two version app.config files and use them properly?
When check in, we only check in the app.config for production.
Please remember, it is not an asp.net web application. In that case, we can have different web.config files.

Yes you can, but you need an extension to do it. I have used SlowCheetah for this in the past.
Use SlowCheetah to add a transform for your release build that changes the log-path. Your app.Release.config transform file could look something like this.
<?xml version="1.0" encoding="utf-8" ?>
<!-- For more information on using transformations
see the web.comfig examples at http://go.microsoft.com/fwlink/?LinkId=214134. -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="logDirectory" value="D:\releaseLogs" xdt:Transform="Replace" xdt:Locator="Match(key)"/>
</appSettings>
</configuration>
You can add a transform for Test and Debug environments as needed.
In your source control you would check in:
An app.config that contains all the keys your application needs
An app.Release.config that contains transforms that changes the keys that need to be different in your Release environment.
When your solution is built, SlowCheetah will apply the correct transforms to your app.config based on the target environment.

Another alternative to extensions is to simply add a Post-Build event in your project:
if "Debug"=="$(ConfigurationName)" goto :nocopy
del "$(TargetPath).config"
copy "$(ProjectDir)\App.Release.config" "$(TargetPath).config"
:nocopy
Copy your App.config to App.Release.config and change as needed, when you publish as Release the appropriate file will be used.

Related

Set two different environments in a dll?

I have implemented a dll for consuming an API. It's working properlyn but now I have to allow user to consume the dev and production API's (we have separate environments for dev and production). I donĀ“t know how to do it.
I can implement a switch and allow the user to set production or dev and just change the path, but I'm guessing this is bad practice.
Actually, I have a path stored in app.config. Any suggestions on how to implement this or is the only way to send the user two dll's, one for production and one for dev?
The correct way to do this would be:
to store the path in app.config
create environment specific transforms for the config file
transform the config file during deployments
Sample config:
<add key="apiUrl" value="http://localhost/myapi" />
And corresponding transform file
<add key="apiUrl" value="http://devhost/myapi" xdt:Transform="Replace" xdt:Locator="Match(key)" />
You can use plugins like SlowCheetah to do the transformation.
Alternatively, you can use MSBuild tasks to do the transformation as well:
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
<Target Name="TransformWebConfig">
<TransformXml Source="C:\myapp\app.config"
Transform="C:\myapp\app.dev.config"
Destination="C:\myapp\bin\<web.config or in case of exe, product.exe.config>"
StackTrace="true" />
</Target>
Note: DLL files in .Net cannot have config files. So I'm assuming you're referring to the exe or web.config of your product.
Conditional compilation could be an option for this.
It's not too hard to set up. A good article is:
http://www.codeproject.com/Articles/451734/Visual-Studio-Use-Conditional-Compilation-to-Contr

Using Entity Framework app.config how to switch between environments Dev, Stage and Production

I have a windows application accessing Dev database using DataModel.edmx and it works fine. To access stage environment database I have added another StageDataModel.edmx. So there are two connection strings in app.config:
and
How do I switch between databases in app.config based on environment?
Thanks in advance!
Normally it should be the other way around - create one EF edmx model and two (or more) configuration files for every environment.
At my work, we have three environments:
Release = Production
Stage = before GO live (copy of production, final tests)
Debug = new development, dev team tests
For the three environments, we have three databases, that are (almost) similiar to each other. We create our model from the DEV database. Every project that communicates with the database has always three connection strings with different credentials.
In order to achieve this, you need to:
1) create different build platforms using the Visual Studio configuration manager (in my example, there are three build configurations - Dev/Stage/Release):
2) extract the connection string configuration from the app.settings file. Instead of specifying the connection in the app.settings file, use the configSource parameter like this (the app.config looks like this):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings configSource="App.ConnectionStrings.Config" />
</configuration>
3) now create different files for every build configuration, named after each build configuration (the wording must be exact!) and containing different servers or databases
App.ConnectionStrings.Debug.config
App.ConnectionStrings.Stage.config
App.ConnectionStrings.Release.config
Foer example the Debug can look like this:
<?xml version="1.0" encoding="utf-8" ?>
<connectionStrings>
<add name="Named.ConnectionString"
connectionString="metadata=res://*/Abstraction.DbDataContext.csdl|res://*/Abstraction.DbDataContext.ssdl|res://*/Abstraction.DbDataContext.msl;provider=System.Data.SqlClient;provider connection string="data source=sql.server.address;initial catalog=People;integrated security=False;user id=DbUser;password=DbPassword;multipleactiveresultsets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
4) now open your project settings in Visual Studio, go to Build Events and in the Post-Build event command line tell Visual Studio to take on every build the file named after the currently selected build platform and copy it with the specified (in the app.config) name to the output directory:
copy $(ProjectDir)\App.ConnectionStrings.$(ConfigurationName).config $(TargetDir)App.ConnectionStrings.config
Now when you build and start your application, the configuration depends on the build configuration, so you can even debug your application connected to the LIVE environment (when the currently chosen build configuration is Release).
More info on how to use external configuration files and connection strings, can be found in this MSDN article.
A good Entity Framework quick start.
I think you are asking how to use different app.config files for debug/release.
Just name them app.Release.config or app.Debug.config and have the debug or release settings in either one.
If its more complicated than that, you can install a tool such as SlowCheetah to modify XML files, you just need to set up different build configurations.

How can I make a DLL ApplicationSettings class which reads from library.dll.config?

I'm creating a plug-in for another application as a DLL, which needs to have settings that can be configured without recompiling the DLL. I created a settings class through Visual Studio as I usually do with application projects. When I build my project a libraryname.dll.config file is created and copied to the output directly.
But, as may other people have already found and written about, this file is never used. Instead if I want to modify these DLL settings I need to merge the settings into the settings file for whatever application that is using the DLL.
The problem I have with this is the calling application is not my application, so I'd rather the configuration of my plug-in live with the rest of my files for my plug-in.
In the past I've used System.Configuration.ConfigurationManager.OpenExeConfiguration() to read a settings file for the DLL like this.
public static string GetSettingValue(string key)
{
string assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
var config = ConfigurationManager.OpenExeConfiguration(assemblyPath);
var keyVal = config.AppSettings.Settings[key]
return keyVal.Value;
}
Which would read from a settings file like this
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="URL" value="http://www.acme.com" />
<add key="EnableAdmin" value="False" />
</appSettings>
</configuration>
However, I really like newer type safe ApplicationSettings class that is created by visual studio rather then then using <appSettings> which can only store strings.
So what I'm wondering is if there is some way I could override a method or two in the ApplicationSettings class created by visual studio to get it to read from the DLL config file by default? It's not really clear to me exactly where it's being determined which config file should be read.
You can try to merge the applicationsettings file in the calling application. This SO thread explains it pretty well.
How to load a separate Application Settings file dynamically and merge with current settings?
If you do not want to mess with editing the calling application, you can just use the Configuration class like you are doing. Here's another example. I've used this approach when I needed to call a WCF service through COM.
http://www.twisted-bits.com/2012/04/use-a-net-configuration-file-with-a-class-library-dll/
Copy the applicable section to the web.config of the main site or app.config of the main executable, then ConfigurationManager.AppSettings["URL"] works just fine.

Can we share some contents of App.config between projects?

I have two independent projects in my Visual Studio 2008 solution. Both has its own App.config. But in one project, I need one or two properties defined in another project's App.config. Is it possible to share part of the App.config contents from other project?
Yes - of course. Any configuration section can be "externalized" - e.g.:
<appSettings configSource="AppSettings.DEV.config" />
<connectionStrings configSource="MyConnection.config" />
or
<system.net>
<mailSettings>
<smtp configSource="smtp.TEST.config" />
vs.
<system.net>
<mailSettings>
<smtp configSource="smtp.PROD.config" />
Any configuration section can be put into a separate file that can be shared between projects - but no configuration section groups, and unfortunately, it's sometimes a bit tricky to know which is which.
Also, in some cases, Visual Studio will complain (using red wavy underlines) that the "configSource" supposedly isn't valid - but it is - it's defined on the ConfigurationSection object in the .NET config system.
UPDATE:
another feature that hardly enough developers seem to know and use is the ability in Visual Studio to add existing files from a different project as a link:
With this, you can add links to files into your local project, and they'll always be kept up to date. Great productivity booster if you need to do some file-level sharing (like for common configuration files or such)!
Try this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings file="PROD.config">
<add key="common.Currency" value="GBP" />
</appSettings>
</configuration>
Only the "running" app.config is used, but you can go external like marc_s says.
You can also create a .Settings file that's "shared". Go to the "shared" project properties, the Settings tab on the left, create a setting with Application scope, and set the Access Modifier on top to Public. In your other project you can then use ClassLibrary1.Properties.Settings.Default.SettingName to access it. It will be strongly typed, but you may need it at compile time.
Something I like to do, especially when trying to coordinate ServiceModel elements between libraries and tests is to use configSource to fragment the config in the target library and simply link/copy always the fragments in my test projects.
That way I only maintain in one location.
You could take it one step farther and simply have a common directory in the solution and link the fragments in all projects.
In that situation, I would think using a Database to store some configuration data would be ideal. Each app does its own thing, but they look to a shared database to get those common pieces of information.
EDIT: I spoke too soon! Looks like both the OP and I learned something about config files =D

Multiple .NET Configuration Files and Setup Project Problem

In order to handle settings for different deployment targets, I moved application settings from app.config to its own file and included that file in app.config via configSource. I also created a settings file for each target.Here is an illustration:
Project A
app.config (references settings.config)
settings.config
settings.Release.config
settings.Debug.config
During post-build, I copy the appropriate settings.{configuration}.config to the output directory. This is working fine so far and I can see settings.config file in the project output directory containing settings for the current build configuration: Release, Debug, etc.
However, I am having a problem with the setup project that I have for this project (Project A). Initially, it was not including settings.config file. So I set the build action for settings.config file as Content and I added content files from Project A to the setup project. This ensured that settings.config file was included in the setup. However, since the setup project appears to be picking settings.config file from the project directory instead of the output directory, settings.config file included in the setup is not what it should be. I want the one from the output directory to be included in the setup program since that one is the correct one for the current build configuration. I tried the following:
Added settings.config as a file to the setup project. However, it seems like I can only specify absolute path. So when I add it from the output directory of a particular build configuration (..bin\debug\settings.config), it does not work in other build configuration since (..bin\debug\settings.config) does exist in the directory specified. I looked into using relative paths or dynamic paths in the setup project where the build configuration could be specifed as part of the path but I could not find anything.
I considered using pre-build event to actually modify settings.config file in the project directory and then have it copied over the output directory by setting its 'Copy to Output Directory' to copy always or copy if newer. This should ensure that the appropriate settings.config is copied to the output directory just like the post-build based solution and should also ensure that the contents of settings.config file is updated before the setup project includes it. However, I don't like this solution because I would have to make sure settings.config file is writeable before I can make any changes since it is source controlled. If it is readonly, then I need to flip it to writeable, make changes, and then set it to readonly again. It is adding extra complexity.
I was wondering if anyone has a better idea or knows a setup project trick that allows me to include settings.config file appropriate for the current build configuration in the setup program.
Thanks
If I had to approach this problem, I'd start by asking the following question:
Why does settings.config have to be under source code control if settings.Debug.config or settings.Release.config provide the same information?
The answer, if I read your question correctly, is because you needed to force a settings.config file to appear as part of the build output. I'm guessing this is because your setup project is using the built in "Primary output" choice.
What you can do instead is add that file to your setup project as an explicit file reference. Right-click on the setup project and choose add / file, then select the file you want to include. As you'll notice (unless it's been fixed in VS2008 which sadly I'm not yet allowed to use at work), there is a very annoying limitation placed on manually added files - there is no way to make the path build configuration aware. You can work around that by copying the appropriate settings.config file to a common location (e.g. bin/Configuration) and picking it up from there. This does limit you to building Debug and Release versions sequentially, rather than in parallel, but for many this probably isn't a huge problem.
If you aren't required to use VS setup projects, I strongly encourage you to take a look at WiX (Windows Installer XML - see http://wix.sourceforge.net/ for more information). That will easily allow you to accomplish what is necessary, although if you are unfamiliar with the internal workings of Microsoft Installer the initial learning curve could be a little steep. Microsoft use WiX themselves for some pretty significant setup tasks (e.g. Office 2007, SQL Server, etc.). It had been hoped that WiX would become part of Visual Studio (for VS 2010), but sadly that is no longer the case.
I decided to go about achieving the same result (being able to have different configuration settings for different target environments) in a different way. So here is how I implemented it and it is working great. I read some of the posts here at SO about XmlMassUpdate task from MSBuild Community Tasks and decided to utilize it. Here is what I did:
1) For each project that needs to have different settings depending on the target environment, I added an xml file called app.config.substitutions.xml or web.config.substitutions.xml to the project. So, the project looked like
Project A
app.config
app.config.substitutions.xml
app.config.substitutions.xml file has the settings substitutions that XmlMassUpdate will process and apply to app.config file. Below is a sample substitution file that I use:
<configuration xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
<substitutions>
<Development>
<appSettings>
<add xmu:key="key" key="SomeSetting" value="DevValue" />
</appSettings>
</Development>
<Test>
<appSettings>
<add xmu:key="key" key="SomeSetting" value="TestValue" />
</appSettings>
</Test>
<Release>
<appSettings>
<add xmu:key="key" key="SomeSetting" value="ReleaseValue" />
</appSettings>
</Release>
</substitutions>
</configuration>
For details on how to specify substitutions, take a look at the documentation for XmlMassUpdate or just do a search on it.
2) Now I need to run XmlMassUpdate as part of build automation (TeamBuild/MSBuild). So in BeforeCompile in TeamBuild build definition file (basically a proj file), I added the following to run XmlMassUpdate on config files that have a corresponding .substitution.xml file
<PropertyGroup>
<SubstitutionFileExtension>.substitutions.xml</SubstitutionFileExtension>
<TargetEnvironment>Test</TargetEnvironment>
</PropertyGroup>
<Target Name="BeforeCompile" Condition="'$(IsDesktopBuild)'!='true'">
<CreateItem Include="$(SolutionRoot)\**\app.config;$(SolutionRoot)\**\web.config">
<Output ItemName="ConfigurationFiles" TaskParameter="Include"/>
</CreateItem>
<CreateItem Include="#(ConfigurationFiles)" Condition="Exists('%(FullPath)$(SubstitutionFileExtension)')">
<Output ItemName="ConfigFilesWithSubstitutions" TaskParameter="Include"/>
</CreateItem>
<Message Text="Updating configuration files with deployment target specific settings..."/>
<XmlMassUpdate
ContentFile="%(ConfigFilesWithSubstitutions.FullPath)"
SubstitutionsFile="%(ConfigFilesWithSubstitutions.FullPath)$(SubstitutionFileExtension)"
ContentRoot="/configuration"
SubstitutionsRoot="/configuration/substitutions/$(TargetEnvironment)"/>
</Target>
Note that config files are read-only during the build, I make sure to set them writeable before running this task. I actually have another custom MSBuild task that runs before XmlMassUpdate that handles common settings throughout all of the config files such as connection strings. That task makes the config files writeable. I also don't check modified config files back to the source control. They're (appropriate config file for the deployment target) included in the installer.

Categories