Prevent Config File From Publishing With Click-Once Deployment - c#

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.

Related

Excel DNA - Best Way to Use Config Transforms

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

Using external config file for connection strings in multiple projects

I want to know if there is a better way to use connection strings in external files in my solution, since my solution has 8 separate projects, all using the same connection strings. According to this:
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/connection-strings-and-configuration-files#using-external-configuration-files
using an external file (for connection strings) is trivial, and can be easily done (using something like configSource="connections.config). However, in order to make this work, We have to follow these guidelines:
The external file has to exist within the project folder
The external file has to have the property "CopyToOutputFolder" set to true
In my case, this can be done, but it's problematic to manage this throughout all 8 projects, especially if I need to add a new connection string, change one of the settings (target database, username, password), or when I need to add a new project.
--FYI: each of these projects are web jobs that are deployed to an Azure server. Adding a new web job for a new feature, new utility, etc., or removing an old web job for any number of reasons is not uncommon. This solution is constantly changing, which adds to the difficulty of managing these settings within each project separately. Also, connection string management on the production server is not problematic, since each web job inherits these connection strings from the parent app service.
I would like to know if any of the following is possible;
Can I use a separate file that is NOT within the project folder for the connection strings?
Can I load connection strings dynamically (at run-time) into the configuration manager? (one note on this - I know this is possible, but I need to be able to do it without affecting the underlying app.config file)
Is there another type of ConfigurationManager that is commonly used to load these connection strings into the solution, that will meet my requirements?
Although this question is over a year old, I thought an up-to-date answer would be useful for any Windows desktop coders wanting to reference connection strings outside the project folder's app.config etc. This would be useful for sharing 1 config file for multiple projects, having to only change connection string in 1 centralised file.
The basics of telling App.Config to use a different file for connection strings, is straightforward; however, .NET appears NOT to be able to parse this external file, if it is either NOT in the project's root folder, or a subfolder(s) within that project. Let's see this by looking at the most basic example:
in the project's App.config, within the <configuration> tag, use the code below ('configSource' points to another file to read the connection strings):
<configuration>
<connectionStrings configSource="ExternalConnectionStrings.config"/>
</configuration>
Create ExternalConnectionStrings.config, with the following code:
<connectionStrings>
<clear/>
<add name = "ConnString1"
connectionString = "Server=myServer;Trusted_Connection=True;Database=myDB;Persist Security Info=false"/>
<add name = "ConnString2"
connectionString = "Server=tcp:azureserver.database.windows.net,1433;Database=AzureDB;User ID=**;Password=**;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Persist Security Info=false"/>
</connectionStrings>
Save this config file in the same folder as your project's App.config and mark this file's property to 'Copy to Output Directory' or 'Copy if newer'.
This is the 'textbook' way of referring to connection strings from another file other than App.config. However, this may not be that useful: how to have this external file in a completely different folder from the project folder?
To do this, copy that same ExternalConnectionStrings.config to a folder OUTSIDE the project or solution folder, eg. C:\ConnectionStringsFolder\. REMOVE this config file from the project folder where we previously copied/created it (otherwise the following instructions will not work).
Keep App.config the same (making sure the ExternalConnectionStrings.config is not present in the project folder). Use the Windows mklink command to associate ExternalConnectionStrings.config to an external folder, with the following command prompt command:
mklink ExternalConnectionStrings.config C:\ConnectionStringsFolder\ExternalConnectionStrings.config
Windows should return with a 'symbolic link created for....'; make sure you did NOT have that particular config file present in the project folder where app.config sits.
You should see the ExternalConnectionStrings.config listed within eg. Visual Studio; make sure you mark this to COPY to the output folder (I use 'Copy if newer', which will pick up any changes to the external config file ONLY after a rebuild of the project).
This answers Matt Spinks' question 1; for question 2, the following method will return all connection strings found within the external file (as pointed to by App.config):
using System.Diagnostics;
using System.Configuration;
static void GetConnectionStrings()
{
ConnectionStringSettingsCollection cStringsSettings = ConfigurationManager.ConnectionStrings;
if (cStringsSettings != null)
{
foreach (ConnectionStringSettings cstrings in cStringsSettings)
{
Debug.WriteLine(cstrings.Name);
Debug.WriteLine(cstrings.ConnectionString);
}
}
}
This is currently working in Visual Studio 2019, with .NET Core 3.1, a WPF application, on Windows 10.
You don't mention which version of dotnet you are using, however if you are using dotnet core the application configuration can be sourced from environment variables.
I think this could solve your problem because you don't need to track any additional files between your projects and in my opinion makes a lot of sense because any secure data would not be visible to any developer or be stored in any repository. Only devops would know about it when they set it initially. Also this gets your closer to the 12 factor app https://12factor.net/.
To use this make sure that your Startup.cs file includes a section to load the environment variables such as
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", true, true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
.AddEnvironmentVariables()
.Build();
dotnet core Environment Variable cnfiguration provider
You can probably create a bat file to set everything initially
setx connection_string="Server=xxxxxxxxx" /M
This will create your environment variables and set the values you specity.
Hope you find this useful.

IIS Session Lost on Publish Web

Previously with my Web project in Visual Studio 2012 I was able to hit the 'Publish Web' button and as long as I did not make any changes to any .config or .cs files most of the time my session data would persist so I wouldn't have to log in again every time I make a small change to a .css or .html file.
After messing around with some settings in order to get debugging functioning with w3wp.exe now the session data is lost every single time I click Publish Web, even if I made absolutely no changes between publishes.
I don't know what I did to change this but I really need to be able to make changes to static files without having so sign in every single time. How do I stop the session from being killed?
It depends on what you're publishing. Even if you didn't make any changes knowingly, the app domain will unload if:
web.config was copied again (contents don't matter)
bin folder was modified (again, same dlls with newer timestamps are considered modification)
AFAIK, Publish always updates web.config. One thing I'm not sure is whether it updates web.config if you don't have any transforms (.debug.config or .release.config) or not.
There are couple of things you can try:
Set web.config's Build Action to "None". That'd prevent it being copied to output altogether.
Define a new Build Configuration, say "Static Content". Using this Build Configuration, define a new publish profile, say "Static Content". Add these lines to your .csproj file
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
...
<OutputPath>bin\</OutputPath>
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
<ExcludeFilesFromDeployment>web.config</ExcludeFilesFromDeployment>
<ExcludeFoldersFromDeployment>bin</ExcludeFoldersFromDeployment>
</PropertyGroup>
This would prevent these 2 folders from being deployed so your app domain won't unload and session won't be lost. And you can still use the other profile to do a full release when needed.
In your Publish > Settings > File Publish Options, ensure you have "Delete all existing files..." option unchecked.
Hopefully, one or all of these workarounds will resolve your issue.
Update: Based on the comments, here's a simple AfterBuild Target that recursively copies only changed files to publish folder. Simply copy the following code into your .csproj file and tweak the paths appropriately.
<!-- define static content to be copied over -->
<ItemGroup>
<SourceFiles Include="CSS\**\*.css" />
<SourceFiles Include="Scripts\**\*.js" />
</ItemGroup>
<!-- The target that gets executed after build finishes and copies files recursively -->
<Target Name="AfterBuild">
<Copy
SourceFiles="#(SourceFiles)"
DestinationFolder="C:\Publish\YourApp\%(RecursiveDir)"
SkipUnchangedFiles="True"
/>
</Target>
Now when you build, you should see the static content getting published to your publish folder.
Notes:
%(RecursiveDir) copies files recursively, which helps in rebuilding the folder tree. Helpful if you have nested folders such as css\fonts and css\images.
Copy task has several other attributes (such as ContinueOnError, OverwriteReadOnlyFiles) that you may want to tinker with.
You can also use standard VS macros in the destination path (e.g. $(SolutionRoot), $(OutputDir) etc.).
Do you mean asp.net session? If yes then it is restored each time when the application pool is restarted . It could be caused by:
web config change
bin folder content change
IIS app pool recycle
Generally it is a wrong practice to rely on session data. You have to always check for the data existence and restore if not exit without forcing the user to log in.
But you can keep the session alive if you run it in SateServer or SqlServer mode:
Session-State Modes
Solution 1:
Setup a new site in IIS to hold all of your static files. E.g.
-Make sure it uses a different Application Pool than your other site
NewSite/Css/.css
NewSite/Scripts/.js
NewSite/JQuery
NewSite/BootStrap
(don't actually create this structure, you can manage it with a new vs project)
etc
Give it a localhost host header (MachineName and Port) internal access only.
Now Create a new Project in the Solution with your existing project, move said files to it matching a structure like above.
Setup a new publish profile to deploy your css, scripts, etc etc to the New site you made http://{machinename}:port
Call the Profile something like Dev_PublishStatics or Prod_PublishStatics (w/e you want)
Now you can make changes to CSS/Scripts in Project 2 and publish them with resetting Site A
-Lastly
In your Main site, Create virtual directories that point to the directories for Css, Scripts etc etc in the site you made above.
--Notes
You can also move ASPX files etc etc to the new Site and map them via virtual directories too if you want, but the dlls would need to be in both sites Bin folders. But it works, just remember that if you changed code you need to publish to both sites.
Solution 2:
Change the app pool settings,
IIS Manager
-> Application Pools
->-> Select Site Application Pool
->->-> Advanced Settings on the actions menu
Now set Disable Recycle for Configuration Changes to True, this will prevent the site from resetting on configuration changes. You will need to remember to reset it yourself when new code needs loaded.
I also recommend setting
Start Mode = Always Running
Disable Overlapped Recycle = true

ConfigurationManager.AppSettings getting null?

I did not realize that: 'have a web.config in a separate class library and' was reading the web.config app setting from different web application.
I am using VS2010 target framework 3.5
I don't know what is wrong here but I am getting null when I try to get ConfigurationManager.AppSettings["StoreId"];
private string _storeid = GetStoreId;
public static string GetStoreId
{
get
{
return ConfigurationManager.AppSettings["StoreId"];
}
}
web.config:
<appSettings>
<add key="StoreId" value="123" />
</appSettings>
If you are UNIT TESTING you need A COPY of the APP.CONFIG inside the UNIT TEST PROJECT
Update
You can have an AfterTargets in your CsProj file that copies the config:
<Target Name="CopyAppConfig" AfterTargets="Build" DependsOnTargets="Build">
<CreateItem Include="$(OutputPath)$(AssemblyName).dll.config">
<Output TaskParameter="Include" ItemName="FilesToCopy"/>
</CreateItem>
<Copy SourceFiles="#(FilesToCopy)" DestinationFiles="$(OutputPath)testhost.dll.config" />
</Target>
Problem
The usual cause for this is due to context.
Cause
When you have a solution with two projects, if the App/Web.Config is in the main project it wont work if the context of the running application is the second project such as a library, unit test, etc.
Conundrum
To read values from the config in other projects (with System.Configuration) you'll need to move/copy the config file to the project with the running context. Unfortunately duplicating files defeats the tenants of good programming; OOP, Source Code Management, SOLID, etc.
Cool Solution
A nifty solution is adding config file shortcuts in other projects so you only update one file:
It would be nice to divide the contents of config files across project's. Elegantly, like Sharing Assembly Files as per answer #2: https://stackoverflow.com/a/15319582/495455 but alas it's by context
Disclaimer ;) This post is not to answer OP as it is too late but definitely it would help the readers who end up to this page.
Problem I faced : ConfigurationManager.AppSettings["uName"] returning null in my C# web api project.
Basic Things I checked for :
1) In code ConfigurationManager.AppSettings["uName"] , I was using exact key 'uName' as I had in web.config file,
i.e
<appSettings>
<add key="uName" value="myValue" />
</appSettings>
Checked that I haven't mis typed as userName instead of uName etc.
2) Since it is a Web API project it would have a file as web.config instead of app.config , and that too in root folder of your project. [refer the image].
Solution :
The solution that worked for me ,
Changed ConfigurationManager.AppSettings["uName"] to WebConfigurationManager.AppSettings["uName"]
and
made sure that I had
<appSettings>
<add key="uName" value="myValue" />
</appSettings>
in the right file ie.
Right file is not web.config in View folder
neither the debug or release web.config
and:
<appSettings>
<add key="StoreId" value="123" />
</appSettings>
is located in the web.config file of your ASP.NET application and not in some app.config file you've added to your class library project in Visual Studio, right? You can't be possibly getting null if this is the case. If you've added this to an app.config of you class library project in Visual Studio then getting null is perfectly normal behavior.
I just got answer DLL are called from another project not in the project where there are create.so entries in App.config should b move to calling project config file.
For example i have 2 project in my solution one class library and other console application.i have added class library reference in Console application.So if i add app.config file in class library project it through null exception.it works when i added app.config in console application.Hope it works
App settings are loaded into ConfigurationManager.AppSettings, but User settings (in Properties settings in your project properties) are not.
In Visual Studio, right-click on the config file, select Properties, and then change "Copy to Output Directory" to either "Copy always" or "Copy if newer".
Alternatively, manually add the following section as a child of the element in your .csproj file (this one is for "Copy always" for file "App.config"):
<ItemGroup>
<None Update="App.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
I tried all of these solutions but none worked for me. I was attempting to use a 'web.config' file. Everything was named correctly and the files were in the proper location, but it refused to work. I then decided to rename my 'web.config' file to 'app.config' and just like that, it worked.
So if you are having this issue with a 'web.config' file be sure to rename it to 'app.config'.
This happened to me when I was testing a Class Library (.dll). They were both in the same project but the App.config for the library had the settings I needed. The App I had written to test needed the settings because it was running the library.
I got this problem as I copied a project from the file explorer and renamed the project. This copied the Debug folder and as I didn't have it set to 'Copy if newer' it didn't overwrite the old App.config file.
Just delete the Debug folder and rebuild. Hope that helps someone.
I agree with above answer and I would like to add few more points
you should make sure you don't put space before and after the :
see code below:
private static string Client_ID = ConfigurationManager.AppSettings["ida:ClientId"];
if you put space between ida: ClientId it will not work and will return null
make sure your key value names are correct
you can try WebConfigurationManager
Happened to me just now, only when calling it from another project.
Apparently, at the other project, the reference has not been defined as a Service Reference but rather as a Connected Service. I deleted the reference and added it again.
string setting = ConfigurationManager.AppSettings["Setting"];
Make sure config file is in the same folder as code referencing it. Create a
helper class if it is not. Duplicating this could cause confusion should
someone forget it exists in two places.
Keep app settings in an app.config and not a web.config for AppSettings.I had this issue with a key in the web.config.

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