Visual Studio: differentiate app.config for debug and release mode - visual-studio

Is there a way to automatically use a separate app.config when building in release mode?
In other words, I want to test with one app.config, and release with another.
Currently, I keep a separate copy called app.config.production, and manually overwrite bin\Release\Application.exe.config after building for release.

Unload the project in Solution Explorer via the context menu.
Edit the .csproj file via the context menu and add this:
<PropertyGroup>
<AppConfig>App.$(Configuration).config</AppConfig>
</PropertyGroup>

I have recently posted a supremely belated response to a similar SO topic:
https://stackoverflow.com/a/27546685/2798367
I will repeat it here for clarity:
This is somewhat late to the party, but I stumbled upon a nice way of implementing the web.transform approach for app.config files. (i.e. it makes use of the namespace http://schemas.microsoft.com/XML-Document-Transform)
I think it is "nice" because it is a pure xml approach and doesn't require 3rd party software.
A parent / default App.config file is descended from, according to your various build configurations.
These descendants then only override what they need to.
In my opinion this is much more sophisticated and robust than having to maintain x number of config files which get copied in their entirety, such as in other answers.
A walkthrough has been posted here: http://mitasoft.wordpress.com/2011/09/28/multipleappconfig/
Look, Mom - No explicit post-build events in my IDE!

A clean solution is to group 2 files App.Debug.config and App.Release.config into App.config and change the good file into App.config depending on the configuration at compile time:
<ItemGroup>
<None Include="App.config" />
<None Include="App.Debug.config">
<DependentUpon>App.config</DependentUpon>
</None>
<None Include="App.Release.config">
<DependentUpon>App.config</DependentUpon>
</None>
</ItemGroup>
<Target Name="SetAppConfig" BeforeTargets="Compile">
<Copy SourceFiles="App.Debug.config" DestinationFiles="App.config" OverwriteReadOnlyFiles="true" Condition=" '$(Configuration)' == 'Debug' " />
<Copy SourceFiles="App.Release.config" DestinationFiles="App.config" OverwriteReadOnlyFiles="true" Condition=" '$(Configuration)' == 'Release' " />
</Target>
With this solution you will get something like this in Visual Studio:

A simple and fast way is to create a second file "App.release.config" and insert this pre-build event:
IF $(ConfigurationName) == Release COPY /Y "$(ProjectDir)App.config" "$(ProjectDir)App.debug.config"
IF $(ConfigurationName) == Release COPY /Y "$(ProjectDir)App.release.config" "$(ProjectDir)App.config"
And this post build event:
IF $(ConfigurationName) == Release COPY /Y "$(ProjectDir)App.debug.config" "$(ProjectDir)App.config"
This might be a bit odd, but it will allow you to keep using the .Settings files as debug settings, that are still linked to the App.config. The App.release.config must be build by hand, but it's pretty easy to switch this functionality.

I highly recommend SlowCheetah for app.config transformations. Visit this nuget gem here Visual Studio Gallery

Similar to top answer but with this approach you can see the actual file if preferred and intellisense doesn't complain in csproj file:
<Target Name="SetAppConfig" BeforeTargets="Compile">
<Copy SourceFiles="debug.config" DestinationFiles="app.config" OverwriteReadOnlyFiles="true" Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " />
<Copy SourceFiles="release.config" DestinationFiles="app.config" OverwriteReadOnlyFiles="true" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
</Target>

I don't know if this helps, but app.config will recognise the standard MSBUILD substitution strings such as $(Configuration).

Related

Different `google-services.json/GoogleService-Info.plist` for iOS/Android project based on build configuration in Xamarin

So I have a requirement where my project should use different GoogleServices files for Android/iOS while using different configurations like for eg while I am using the debug configuration it should use the debug version of the file and in the release, it should use the release version.
Something similar to
Xamarin firebase different google-services,json for different build configurations
When I follow the accepted the answer I get a compile-time error saying
The command COPY /Y "$(ProjectDir)GoogleServices\google-services-development.json" "$(ProjectDir)google-services.json" exited with code 1.
I tried clean build and cleaning bin/obj nothing changed.
So I tried the other solution mentioned here and what happens is the GoogleServices files(all of them) are excluded from the project and nothing happens if I build and run. I am unsure if this is even working or not.
I have added the following lines in my csproj for release and debug respectively
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<GoogleServicesJson Include="Dev\google-services.json">
<Link>google-services.json</Link>
</GoogleServicesJson>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Release'">
<GoogleServicesJson Include="Prod\google-services.json">
<Link>google-services.json</Link>
</GoogleServicesJson>
</ItemGroup>
Where dev and prod are root folders in my native android project
Any suggestions are welcome.
You have to edit *.csproj file.
Using a solution to use multiple Info.plist (LogicalName tag) and Condition tag you can play with any other files all you want.
For Android I added two *.json files to Resources folder and added this snippet to my *.csproj file:
<ItemGroup Condition=" '$(Configuration)' != 'Release' ">
<GoogleServicesJson Include="Resources\dev-google-services.json">
<LogicalName>Resources\google-services.json</LogicalName>
</GoogleServicesJson>
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'Release' ">
<GoogleServicesJson Include="Resources\release-google-services.json">
<LogicalName>Resources\google-services.json</LogicalName>
</GoogleServicesJson>
</ItemGroup>
In this example I use release-google-services.json for the "Release" build configuration, and dev-google-services.json for any other configurations.
Same for iOS. I added two *.plist files to root folder and added this snippet to my *.csproj file:
<ItemGroup Condition=" '$(Configuration)' != 'AppStore' ">
<BundleResource Include="Dev-GoogleService-Info.plist">
<LogicalName>GoogleService-Info.plist</LogicalName>
</BundleResource>
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' == 'AppStore' ">
<BundleResource Include="Release-GoogleService-Info.plist">
<LogicalName>GoogleService-Info.plist</LogicalName>
</BundleResource>
</ItemGroup>
This approach works for me. I guess it doesn't matter where you put these files and how you name them. Just use the LogicalName that you need.
Also, you can combine it with other variables to compose more complicated conditions. For example, in order to build two *.apk in Release configuration with different *.json files you can:
<ItemGroup Condition=" '$(Configuration)|$(DynamicConstants)' != 'Release|' ">
<GoogleServicesJson Include="Resources\dev-google-services.json">
<LogicalName>Resources\google-services.json</LogicalName>
</GoogleServicesJson>
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)|$(DynamicConstants)' == 'Release|' ">
<GoogleServicesJson Include="Resources\release-google-services.json">
<LogicalName>Resources\google-services.json</LogicalName>
</GoogleServicesJson>
</ItemGroup>
Build your project like this:
msbuild MobileApp.sln /p:Configuration=Release /p:DynamicConstants=DEBUG
When you use DEBUG parameter you build Release apk with dev-google-services.json.
When you omit DEBUG parameter you build Release apk with release-google-services.json.

Copy output binaries to custom path for xproj

I have solution with about 50 projects.
The projects have 2 target frameworks: netcore1.1 and .net 4.6.
All the projects are based on xproj.
So as build result I have binaries in bin/$configuration/$targetfw/.
F.ex. in my case I have binaries in bin/debug/netcoreapp and bin/debug/net462 outputs.
But I need to have copy of bin/debug/net462 content in /bin directory too.
How to make it correctly by script in project.json or smth else for all 50 projcts of solution?
And it would be great if fix wont be visible for git source control.
P.s. Why i need it? Because VS code map tool looks for binaries in bin directly
UPD.
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>9e2d06cb-21aa-4457-ab44-6e67298037e3</ProjectGuid>
<RootNamespace>SmartDoc.Domain.Document</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<SccProjectName>SAK</SccProjectName>
<SccProvider>SAK</SccProvider>
<SccAuxPath>SAK</SccAuxPath>
<SccLocalPath>SAK</SccLocalPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
How to make it correctly by script in project.json or smth else for all 50 projcts of solution? And it would be great if fix wont be visible for git source control.
You can add a custom MSBuild task to copy the binaries from bin/$configuration/$targetfw/ to /bin directory.
To accomplish this, unload your project, edit it, add following code before ending tag </Project>:
<ItemGroup>
<MySourceFiles Include="$(ProjectDir)bin\$(Configuration)\**\$(ProjectName).dll"/>
</ItemGroup>
<Target Name="TestCopy" AfterTargets="Build">
<Message Text ="Copy file to bin folder." Importance="high"></Message>
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="$(ProjectDir)bin"
/>
</Target>
With this target, VS/MSBuild will copy the .dll file to the /bin directory.
Note: Since we have to modify the project file, this fix have to be visible for git source control.
Update:
Could I modify f.ex. Microsoft.DotNet.Props file and add your fix with
Target there?
Yes, you can. After test, it works fine. But I need to explain that we are not recommend this solution, because it may effect all the project which have Microsoft.DotNet.targets imported. So when you use this method, you should pay more attention and should back up that Microsoft.DotNet.targets.
Hope this helps.

Teamcity .Net project, conditional project reference when building in Visual Studio

I have build chains in TeamCity, where the dependent artifact is copied to /bin directory of the main project. The project file references the artifact. That all works.
What I want is to allow a project file include, instead of the binary reference, when building/debugging from Visual Studio. I have tried some approaches, such as using conditionals in the project file, but is there a nice clean way to approach this?
May be there is the part of solution.
May way of using several referencing types of projs.
<ItemGroup Condition=" '$(ReferencedDACPAC)' == '' ">
<ProjectReference Include="..\OmniUS\OmniUS.sqlproj">
<Name>OmniUS</Name>
<Project>{26075a62-f6b0-40c3-baa2-b9a9829da3c4}</Project>
<Private>False</Private>
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
</ProjectReference>
<ProjectReference Include="..\OmniUS_Finance_Jural\OmniUS_Finance_Jural.sqlproj">
<Name>OmniUS_Finance_Jural</Name>
<Project>{c8b0aee7-c2a4-4370-8451-13b455bb5363}</Project>
<Private>False</Private>
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
</ProjectReference>
</ItemGroup>
<ItemGroup Condition=" '$(ReferencedDACPAC)' == 'true' ">
<ArtifactReference Include="..\DacPacs\OmniUS.sqlproj.dacpac">
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
</ArtifactReference>
<ArtifactReference Include="..\DacPacs\OmniUS_Finance_Jural.sqlproj.dacpac">
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
</ArtifactReference>
</ItemGroup>
When I build in TeamCity, I send ReferencedDACPAC as the "System" variable in the build, and thus refer to "ArtifactReference". When i build in VisualStudio, there is no var and the referencing occurs as "ProjectReference".

Copy DLL files to bin directory after one-click publishing in VS2010

I have a web application in VS2010 which has a number of DLLs that need to be copied into the bin directory after doing a publish in VS2010.
I've tried putting the following into my .csproj file (which sits in the root folder of the web applications) but it doesn't seem to work:
<Target Name="AfterBuild">
<ItemGroup>
<_CircularDependencies Include="DLLs\Circular\Dependencies\*.dll" />
</ItemGroup>
<Copy
SourceFiles="#(_CircularDependencies)"
DestinationFiles="#(_CircularDependencies->'bin\%(Filename)%(Extension)')"
SkipUnchangedFiles="true" />
</Target>
For bonus points, I have another set of DLLs copied to be copied post-publish, but I want to use one set when doing a debug publish (for Win32) and a different set when doing a release publish (x86).
Thanks!
OK, I've managed to get this working fully. Thanks to the answers provided above, I've been able to add some MS Build commands to the .csproj file to copy the appropriate DLLs from various folders into the bin folder based on the current build configuration. However as these are unmanaged DLLs (i.e. not .NET) I can't create normal references to them and they fail to be copied during the publish. I got around this by dynamically adding the files to the project as 'content'.
The solution came in three parts. Firstly, create an item group for the files near the top of the .csproj file (I've tried to use generic filenames here to make it clearer), with conditions based on the current build configuration:
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<_UnmanagedDLLs Include="Win32DLLs\*.dll" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<_UnmanagedDLLs Include="x64DLLs\*.dll" />
</ItemGroup>
Then add another item group to include these DLLs (as content, not references) in the build:
<ItemGroup>
<Content Include="#(_UnmanagedDLLs->'bin\%(Filename)%(Extension)')" />
</ItemGroup>
Finally, at the bottom of the .csproj file, I do the copy on the AfterBuild target:
<Target Name="AfterBuild">
<Copy SourceFiles="#(_UnmanagedDLLs)" DestinationFiles="#(_UnmanagedDLLs->'bin\%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
</Target>
It means I can do a debug publish for my windows 32 staging box and a release publish for my x64 production box while keeping my bin folder out of SVN.
Once you get the copy working, separate sets for debug/release is easy with a condition:
<ItemGroup Condition="'$(Configuration)' == 'Release'">
<_CircularDependencies Include="DLLs\Circular\Dependencies\*.dll" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<_CircularDependencies Include="DebugDLLs\Circular\Dependencies\*.dll" />
<_CircularDependencies Include="DebugDLLs\Circular\Dependencies\*.pdb" />
</ItemGroup>
If you want your copy to happen after publish, not after build you need to change your target from:
<Target Name="AfterBuild">
to
<Target Name="AfterPublish">

Is there such a thing as a "content/data only project" in visual studio

I have a bunch of ancillary XML and XSLT files that I want to edit and manage in visual studio.
The files do not logically belong under any code project in my solution and so in order to group them neatly, I have created a "dummy" C# dll project in visual studio and disabled it from building in Debug / release builds).
I wondered if there was a nicer way of achieving the same result (i.e. having all the files visible in solution explorer). What I think really want is a visual studio project type of "content only" but such a thing does not exist (or have I not looked hard enough?).
I have toyed with the idea of adding the files as solution items but then they seem harder to manage because creating a new "solution item folder" does not actually create a folder on disk.
Any one have any ideas?
Visual Studio 2015 has a project type called "Shared Project" which is essentially a content only project with no targets. It's listed under Visual C# but it can be used for any files.
A work colleague has come up with a solution.
He has suggested hand editing the project to remove the DefaultTargets from the Project (and delete a load of now unused properties).
MSBuild complains if there are no targets in the project so he has added three empty targets.
The final project looks something like this
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{541463A7-7CFA-4F62-B839-6367178B16BD}</ProjectGuid>
</PropertyGroup>
<ItemGroup>
... files ...
</ItemGroup>
<ItemGroup>
... files ...
</ItemGroup>
<Target Name="Build"/>
<Target Name="Rebuild"/>
<Target Name="Clean"/>
</Project>
Admittedly, this solution requires more fiddling that I would have liked but seems to achieve what I was after: namely a project that does not aattempt to produce any build output.
Andy posted a link with a solution that's mostly worked for me; basically delete the following line from the project file:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
and add the following lines:
<Target Name="Build">
<Copy
SourceFiles="#(Content)"
DestinationFiles="#(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="Clean">
<Exec Command="rd /s /q $(OutputPath)" Condition="Exists($(OutputPath))" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build">
</Target>
I also found that disabling the project Debug property "Enable the Visual Studio hosting process" (for each configuration) prevented the MyProject.vshost.exe file from being generated.
As David I. McIntosh pointed out in a comment on this answer, if your project is part of a solution with multiple projects and any other projects use the same output path as the content-only project, the above Clean target will delete all of the files in the output path, i.e. the build output of other projects, and would thus only be correct if the content-only project is the first project built (among those sharing the same build output path). The following is a safer and friendlier Clean target for this scenario:
<Target Name="Clean">
<Delete Files="#(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(E‌​xtension)')"/>
</Target>
Then, try creating a Blank solution. Create Empty project. Have your files in respective folders with in the solution folder. From property window, use the Show all files, include those folders into the project. There is no better solution other then this. I hope.
This answer is just a convenient consolidation of the answers above given by Chris Fewtrell and Kenny Evitt, along with the slight modification in my comments above, and a bit more detail on what the declaration of the content items should/could look like:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{541463A7-7CFA-4F62-B839-6367178B16BD}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == '64-bit|AnyCPU'">
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\builds\$(Configuration)\</OutputPath>
<IntermediateOutputPath>..\builds\$(Configuration)\Intermediate\YourProjectName\</IntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<Content Include="fileInProjectFolder.csv" />
<Content Include="SubDir\fileInSubdir.txt" />
<Content Include="..\actualSourceDirectoryOfFile\app.log.basic.config">
<Link>targetSubdirInOutputDir\app.log.basic.config</Link>
</Content>
<Content Include="..\actualSourceDirectoryOfFile\yetAnotherFile.config">
<Link>yetAnotherFile.config</Link>
</Content>
... more files ...
</ItemGroup>
<Target Name="Build">
<Copy
SourceFiles="#(Content)"
DestinationFiles="#(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="Clean">
<Delete Files="#(Content->'$(OutputPath)%(RelativeDir)%(Filename)%(E‌​xtension)')"/>
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build">
</Target>
</Project>
Note that this always copies all the "content" files to the output directory - the options "Copy If Newer", "Copy Always" and "Do Not Copy", as presented in the visual studio GUI ( appears as, for example, <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> in the .csproj file) are ignored.
In my situation, I needed to have a set of configuration files that would be common to many projects. To simply achieve this, I performed the following steps:
Create a Class Library project named "Configuration"
Delete all *.cs files from Configuration project
Put configuration files in a "Configuration" folder in the Configuration project
Copy configuration files to required projects in the post-build event. In Configuration project's Properties > Build Events > Post-build event:
xcopy "$(TargetDir)Configuration\*" "$(SolutionDir)TARGET_PROJECT\$(OutDir)" /i /v /q /s /y
In the above, replace TARGET_PROJECT with your actual project
This will copy all the files in the Configurations folder to the output directory of the project that needs the configuration files (eg. MyProject/bin/Debug, etc).

Resources