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.
Related
I have a project, lets call it 'ProjectX' which needs to use Excel DNA. Development is successful, however, I am unable to resolve one issue. The project uses config transforms to update values in app.config when building for different environments, for example DEV, UAT, and PROD.
Here is the issue: When I build for a certain environment, like DEV, the app.config transforms as expected. However, ProjectX-AddIn64-packed.xll.config does NOT transform, and this is the config that Excel DNA is using inside the XLL. I'm not sure what to do, any help would be appreciated.
Constraints: I can only deploy one file, the XLL.
Things I Have Tried/Researched:
Renaming app.config to ProjectX-AddIn64-packed.xll.config
Using Visual Studio Build Events
Editing ExcelDna.Build.props to try and override the default build/packaging process
App.config transforms are currently not supported in Excel-DNA, as of this writing. One workaround at the moment is to replace the .xll.config files with the contents of the .dll.config file at the end of the build, after the transformation has been applied.
There are many different ways you can choose to do this file replacement... For example, you can run a script in a post-build event, or alternatively add a new MSBuild target to your .csproj file that runs after the ExcelDnaBuild task which copies the file(s).
E.g.
<Target Name="CopyAppConfig" AfterTargets="ExcelDnaBuild">
<Copy SourceFiles="$(TargetPath).config" DestinationFiles="$(TargetDir)MyAddIn-AddIn.xll.config" />
<Copy SourceFiles="$(TargetPath).config" DestinationFiles="$(TargetDir)MyAddIn-AddIn-packed.xll.config" />
<Copy SourceFiles="$(TargetPath).config" DestinationFiles="$(TargetDir)MyAddIn-AddIn64.xll.config" />
<Copy SourceFiles="$(TargetPath).config" DestinationFiles="$(TargetDir)MyAddIn-AddIn64-packed.xll.config" />
</Target>
You can read more about this on our GitHub repo:
Hard coded references to App.config prevents use of config transforms in build. #282
AutoGenerateBindingRedirects doesn't work properly #241
I have created an application in which every installation is differed by the configuration file.
Currently the configuration file (settings.setting) is part of the installer itself.
Is there a way to create an installer without the settings.setting embedded inside it, so will have the setup.exe and a separate settings.setting file?
(So will have 1 installation build, and the installation will copy the setting file to the relevant location as done if it is part of the installation build)
Thanks,
Yoav
Maybe you should try to extract the config file to another file and link it from default config file.
MyApp.exe.config would containt a line like this:
<appSettings configSource="pathtoconfig\MyExternalAppSettings.config" />
Here's a good blog post on this subject.
I'm trying to use Click-Once publishing, trouble is, it's publishing also the Config file, which has the connection strings that I use on my development computer, not the correct ones I use in the production environment. How can I prevent the Config file from being published more than the first time? I tried in properties to not include it in the publishing list, but there is no option to do that.
Config files are part of Deployment since they store all the necessary settings which are used inside Addin.
If I understand the problem correctly then, you want to use some setting, say HOSTURL=http://example.com when Addin is in production environment and HOSTURL=http://localhost when you are developing the Addin and you are expecting all this to automatically without human involvement.
Then, you may try one of these:
[1] Try find the ClickOnceLocation and use settings depending upon value the ClickOnceLocation.
Assuming ClickOnceLocation contains "Debug" while you are developing/debugging the Addin.
//CodeBase is the location of the ClickOnce deployment files
Uri uriCodeBase = new Uri(assemblyInfo.CodeBase);
string ClickOnceLocation = Path.GetDirectoryName(uriCodeBase.LocalPath.ToString());
if(ClickOnceLocation.Contains("Debug"))
{
URL = "http://localhost";
}
else
{
URL = //from app.config
}
[2] Updating the app.config by using build configurations
There are some tricks you could use so that a different file with the values to the production server get picked up during publish.
You can have two separate config files one for local deployment/debugging and one for a real published or production version of the application. The debugging config file could point to the localhost server whereas the real published config file could point to the real server. You can then configure the build configurations such that the appropriate config file is picked up depending on the Active build configuration.
To add two different app.config files to the project, you can update the reference to app.config in your project file. The app.config is defined in the project file (vbproj or csproj) with the following xml:
<ItemGroup>
…
<None Include=”app.config” />
</ItemGroup>
There may be other nodes in the ItemGroup along with the app.config node. Delete the just app.config from this ItemGroup node and create a new ItemGroup under the node with the following xml:
<ItemGroup Condition=” ‘$(Configuration)|$(Platform)’ == ‘Debug|AnyCPU’ “>
<None Include=”app.config” />
</ItemGroup>
<ItemGroup Condition=” ‘$(Configuration)|$(Platform)’ == ‘Release|AnyCPU’ “>
<None Include=”publishedapp.config” />
</ItemGroup>
This basically means that the regular app.config file will be used when the Active configuration is set to Debug and the modified app.config with the real production variables stored in the “published” subfolder of the project is used when the active configuration is set to “Release”.
You can change the ItemGroup conditions to match other build configurations that you may have defined. One possibility is to have a separate “Publish” configuration defined based on the “Release” configuration but only used when you are actually going to publish an application.
An additional disclaimer with this process is that the VS project system itself and the designers are not aware of the additional app.config file; Visual Studio is only aware of the original file. The modified app.config with values for a production environment is only used by the msbuild process. So if you update the main app.config through the Settings Designer, the modified app.config will not be updated and you have to manually update the file.
Once you have configured your project appropriately you can simply switch between the different build configurations to change the config file and publish the application from Visual Studio without having to go through the update and re-sign process.
I'm a bit lost!
I have a dll that uses an xml config file for some db connection info. The dll looks for the xml config file in it's own directory and I can't change the dll at all.
Every time I build the project, I must manually copy the config file into a folder way down somewhere in the Temporary ASP.NET Files folder. (I don't understand this but I can live with this manual change)
The problem is that when I publish the project, I can't figure out where to copy the config file to?
Could someone please point me in the right direction? Or maybe show me a way that I can 'bind' the xml config file to the bin folder???
Vauneen
The .NET config file can be confusing to manage. The way it works in a webapp is that the Web.config will supersede any dependencies' app.config files (which is what I assume you're talking about when you say "DLL".)
Basically, in .NET all config info is pulled from the main app project.
See:
App.config seems to be ignored
and
Configuration from App.config isn't being pulled correctly
and finally:
Does a web.config substitute app.config?
will probably help you figure out what you need to know.
Update: Doing some further searching on your problem, it's possible that the code you're incorporating into the .Net Solution is using the "obsolete" ConfigurationSettings which will require you to add a reference to System.Configuration in your references folder (right-click on the project -> "Add References" and go to the .NET tab and select System.Configuration).
Set "Copy to Output Directory" to "Copy always" in properties of the configuration. Then Visual Studio will copy the configuration file automatically after each build and it will be properly published as well.
As part of our development life cycle we have a number of process that we run against the C# source in our projects.
The processes are driven off a GUI that currently reads the *.csproj file to find the source files used within the project. This works fine.
We now have a new requirement to provide some validation processes that require a call out to a web-service. The web-service needs to be provided with some credentials that are project specific. Ideally we could enter and store these credentials within the *.csproj file but I don't see a means of extending it - is there?
We don't really want to introduce a new config. file just for these settings if we can help it. Is it possible to store information like this is the *.csproj file, if not is there any other place to put it.
thanks
The .csproj file is basically an MSBuild file, as such you can extend it with custom values. If you right-click on a project in Visual Studio and choose "Unload Project", the project will "grey out" and you can then right-click again and choose Edit [ProjectFileName].csproj. You can then add something similar to the following:
<PropertyGroup Label="Custom">
<Badger>1</Badger>
</PropertyGroup>
This should be persisted when the project is modified (i.e. files added/removed) and you can retrieve the values from the file, using the method of your choice.
VS projects support "project extensions". These are custom data stored directly in csproj/vbproj files. You can very easily read and write them even from VS. For example, the following VS macro writes such custom setting:
Dim proj As Project = DirectCast(DTE.ActiveSolutionProjects(0), Project)
proj.Globals.VariableValue("MySettingName1") = "My value1"
proj.Globals.VariablePersists("MySettingName1") = True
The following reads it back:
proj.Globals.VariableValue("MySettingName1").ToString
And the code in csproj file looks like:
<ProjectExtensions>
<VisualStudio>
<UserProperties MySettingName1="My value1" />
</VisualStudio>
</ProjectExtensions>
Of course, this is persisted and will not be overwritten by VS.
I know you dismiss it but the most obvious, and probably recommended, place is in the config file. Albeit encrypted.
One config file per project does for most cases and is not a large overhead imho.