I have an ASP.NET application with Web.Config configured with several connection strings.
I also have a Web.Debug.config and Web.Release.config which contain transforms for the strings and are applied when deploying. Which works fine.
Example of transform in the Web.Release.config:
<add name ="ConnectionKey" connectionString="Server=*******" providerName="System.Data.EntityClient"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
However I would like the transform to also be applied on builds so I could run a script building my application and running several tests before publishing.
I tried to add the following code in my project's file (Source : https://gist.github.com/EdCharbeneau/9135216 ):
<Target Name="BeforeBuild">
<!-- Transform the file out to a temp file, sourcing from our Web.config file: -->
<TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config.temp"
Condition="Exists('Web.$(Configuration).config')" />
<!-- Copy the temp file, back over the top of Web.config, the file handle opened by TransformXml is closed now: -->
<Copy SourceFiles="Web.config.temp" DestinationFiles="Web.config"
Condition="Exists('Web.config.temp')" />
<!-- Cleanup after ourselves: -->
<Delete Files="Web.config.temp" Condition="Exists('Web.config.temp')" />
</Target>
But when I check the bin folder it's always the default Web.Config that is present, not the transformed one.
Related
I have a Nuget package that is downloaded to a non-standard location in my project folder.
Is it possible to reference this package in an fsproj or csproj file?
Something like:
<ItemGroup>
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
<HintPath>./external/packages/Contoso.Utility.UsefulStuff.3.6.0/</HintPath>
</PackageReference>
</ItemGroup>
Nuget can have multiple sources for packages, that can be configured with a nuget.config file. Source can be either URL of some site, like nuget.org or private feed from gitlab, or it can be path to local directory, like C:/Packages/.
You should create nuget.config file in a root of repository with following content:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<!-- Make sure everyone have same sources for more reliability -->
<clear />
<!-- Add default nuget source, since we removed it -->
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
<!-- Add new source that will point to directory with *.nupkg files.
Parameter 'key' can have arbitrary text -->
<add key="localFiles" value="./external/packages/" />
</packageSources>
</configuration>
I have a webb aplication where I want to take advantage of the web.debug.config file so that when debugging I use a test database. This does not work for me. I have this in my web.debig.config..
<connectionStrings>
<add name="connStr"
connectionString="Data Source=LocalSqlserverName;Initial Catalog=testdb;Persist Security Info=True;User ID=Myusername;Password=mypassword"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
And in my web.config file this connectionstring point to another database server. But when I debug I can see that the connectionstring in web.config file is used instead of the one in web.debug.config. What am I doing wrong here?
As #esiprogrammer says it normally only transforms on Publish from Visual Studio.
However you can transform Web.config on build. Add this to your *.csproj file:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
<TransformXml
Source="Web.Base.config"
Transform="Web.$(Configuration).config"
Destination="Web.config" />
</Target>
Keep the origin configuration in Web.Base.config. It's enough to enable transformation and it works for any XML config file.
Source:
https://stackoverflow.com/a/35561167/3850405
I currently have the following nuget.config file. With automatic package restore it will create a package folder that is one level up from my solution folder. For example if my solution folder is on my desktop, the package folder will be generated within a /lib folder on my desktop. I would like for it to generate the /lib folder within my solution folder. How do I change the relative path to accomplish this?
<configuration>
<solution>
<add key="disableSourceControlIntegration"
value="true" />
</solution>
<config>
<add key="repositoryPath"
value="../lib" />
</config>
</configuration>
For example,
Bad: \desktop\lib\
Good: \desktop\mysolution\lib\
I tried this:
<config>
<add key="repositoryPath"
value="/lib" />
</config>
..and the package restore directory becomes c:\lib which is unexpected behavior.
In addition, please make sure your NuGet.Config file is added under your solution directory after you use "lib" path in that path.
I discovered that if I remove
<config>
<add key="repositoryPath"
value="../lib" />
</config>
...from nuget.config
Or
if I complete delete nuget.config (and use all defaults)
That the default behavior will be to create and add packages to this folder:
\desktop\mysolution\packages\
and while that is not named 'lib' it hardly matters - my key issue was to get the packages in to the solution folder.
How can I merge and make use of Web.debug.config in visual studio 2010 built-in debugger?
This is a known bug. That feature can be used right now only as part of the deploy process.
https://connect.microsoft.com/VisualStudio/feedback/details/523221/have-web-debug-config-apply-during-development
Please upvote it, if you encounter this too, so this will be fixed ASAP.
This is actually quite simple to do and, believe it or not, it seems this is the way VS is designed to work.
Add the following lines verbatim right before the closing "Project" tag of the .csproj file of the project that contains web.config.
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="Transform">
<MakeDir Directories="obj\$(Configuration)" Condition="!Exists('obj\$(Configuration)')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="obj\$(Configuration)\Web.config" StackTrace="true" />
</Target>
Put the following lines verbatim to the post-build event in the project properties of the project that contains the web.config file. Do this for each build configuration you want the transformations to run for.
"$(MSBUILDBINPATH)\msbuild" "$(ProjectPath)" /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
xcopy "$(ProjectDir)obj\$(ConfigurationName)\Web.Config" "$(ProjectDir)". /F /R /Y
I had solved this in a simpler way, by adding this at the end of the .csproj file, right before the tag. This is similar to keitn's answer, with the difference that it doesn't use a post build event.
<Target Name="BeforeBuild">
<TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>
I didn't want to update the web.config in my project just the one that ends up in the bin folder so here is how I did it.
Add the following to the end of .csproj (just before the final closing project tag)
<Target Name="Transform">
<MakeDir Directories="bin" Condition="!Exists('bin')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="bin\$(TargetFileName).config" StackTrace="true" />
</Target>
Then add the following post build step
"$(MSBUILDBINPATH)\msbuild" "$(ProjectPath)" /t:Transform /p:Configuration=$(ConfigurationName);Platform=AnyCPU
This means that when you build a transform takes place from the debug/release config to WebsiteName.Config file in the output bin directory thus not interfering with the main web.config in the project.
After reading many similar posts and having problems with files not being able to be overwritten or web.config not being accessible because it is read only this is what I got working for me:
<Target Name="BeforeBuild" Condition="$(Configuration) == 'MyAltDebugConfiguration'">
<ItemGroup>
<OriginalWebConfig Include="$(ProjectDir)Web.config"/>
<TempWebConfig Include="$(ProjectDir)TempWeb.config"/>
</ItemGroup>
<Exec Command=""$(DevEnvDir)tf.exe" checkout "$(ProjectDir)Web.config"" />
<Copy SourceFiles="#(OriginalWebConfig)" DestinationFiles="#(TempWebConfig)" />
<TransformXml Source="$(ProjectDir)TempWeb.config"
Transform="Web.$(Configuration).config"
Destination="Web.config" />
</Target>
Notes:
This runs as the BeforeBuild target.
I only want it to run under a certain configuration (an alternative debug environment) and so that is why I have the Condition. When deploying via web deploy the publishing target kicks in and I don't need this target to run.
I don't want to have to remember to check out web.config (only to undo it when I am done) so I check web.config out before beginning the transform. If you aren't using TFS you can remove this line.
Because VS (2010) \ msbuild doesn't want to let go of the Source web.config I use a temp file (thanks to this article for the info: http://www.diaryofaninja.com/blog/2011/09/14/using-custom-webconfig-transformations-in-msbuild)
I tried adding a command to delete the TempWeb.config but VS \ msbuild doesn't want to let go of it. I can live with it as it doesn't get added to TFS.
I know this is old, but I'm facing the same problem. We have Test, Staging, Live configs that replace endpoints, connection strings etc. from the default Web.config
However I would do the following:
Right click on the desired transform config (e.g. Web.Live.config)
Click on "Preview Transform"
Copy everything from right (it's how the Web.config looks with the transformation)
CTRL+A + CTRL+C
Open Web.config file (default one)
Select everything (CTRL+A) and paste it in (CTRL+V)
Run
It's not that many steps and is done pretty quickly when you get a hang of it. Hope this helps. :)
#ologesa:
Your solution needs write access to the original Web.config (you must check-out in TFS).
The better solution is to directly generate the Web.config in the bin folder like keitn does this. When we combine keitn's and your solution we get this one:
<Target Name="BeforeBuild">
<Message Text="Transforming Web.config from Web.$(Configuration).config" Importance="high" />
<MakeDir Directories="bin" Condition="!Exists('bin')" />
<TransformXml Source="Web.Config" Transform="Web.$(Configuration).config" Destination="bin\$(TargetFileName).config" StackTrace="true" />
</Target>
The project I am working on involves reading a lot of service endpoints (url) from a config file. Since the list would be quite large I decided to keep them in a custom config file to keep my web.config clean and small. I included the custom section to my web as below:
<mySection configSource="myConfig.config" />
I works perfectly fine.
But the problem of transformation appears during the deployment of the project to different environments. I have three web.config files:
Web.config
Web.Uat.config
Web.Release.config
While the transformation web.config works, the transformations for custom config files fails at deployment.
Is there an way I can transform the custom config file during deployment?
Visual Studio transforms only web.config files by default.
If you need custom config file with transformation for DEV, UAT, PROD, etc environments, then try to
Use custom extensions for Visual Studio like SlowCheetah - XML Transforms for Config transformation preview functionality.
Add for the project from Nuget SlowCheetah to provide build in transformation.
A little bit details:
Add VS Extension SlowCheetah from Extensions and Updates
Right click on your myconfig.config and choose add transorm:
Inside each defined configurations insert your own transormation rulles like that:
<services xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<service name="WebApplication1.Services.Service2" xdt:Transform="Replace" xdt:Locator="Match(name)" >
<endpoint address="http://localhost:57939/Services/DebugService" behaviorConfiguration="WebApplication1.Services.Service2AspNetAjaxBehavior"
binding="webHttpBinding" contract="WebApplication1.Services.Service2" />
</service>
</services>
Hope it was helpful
I'm going to extend on Andoni Ripoll Jarauta's answer a little.
We were faced with a similar problem. I wanted to pull the connection strings out of the web.config file to limit merge conflicts. I also wanted create a "release" config containing static information when publishing.
...simple enough. Create a custom config file, webdb.config, and update the web.config file.
Ex.
web.config
<connectionStrings configSource="WebDB.config"/>
wedbdb.config (xml version="1.0" is required for transformation)
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
</connectionStrings>
Next add transformation files for webdb.config
WebDB.Debug.config example:
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings xdt:Transform="Replace" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<add name="PRRADDataContainer" connectionString="metadata=~/PRRADData.csdl|~/PRRADData.ssdl|~/PRRADData.msl;provider=System.Data.SqlClient;provider connection string=';Data Source=localhost;Initial Catalog=;User ID=;Password=;multipleactiveresultsets=True;App=EntityFramework';" providerName="System.Data.EntityClient" />
<add name="MyConnectionString" connectionString="Data Source=localhost;Initial Catalog=;Persist Security Info=True;User ID=;Password=;" providerName="System.Data.SqlClient" />
</connectionStrings>
WebDB.Release.config example:
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings xdt:Transform="Replace" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<add name="PRRADDataContainer" connectionString="metadata=~/PRRADData.csdl|~/PRRADData.ssdl|~/PRRADData.msl;provider=System.Data.SqlClient;provider connection string=';Data Source=prod_server;Initial Catalog=;User ID=;Password=;multipleactiveresultsets=True;App=EntityFramework';" providerName="System.Data.EntityClient" />
<add name="MyConnectionString" connectionString="Data Source=prod_server;Initial Catalog=;Persist Security Info=True;User ID=;Password=;" providerName="System.Data.SqlClient" />
</connectionStrings>
Next we need to add an after-build event. This is created by simply editing the CSPROJ file.
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
<TransformXml Source="WebDB.config" Transform="WebDB.$(Configuration).config" Destination="WebDB.config" />
</Target>
Now when I run locally I'll get WebDB.Debug.config and when I publish my code I just need to make sure to select "Release" as the configuration source. In both cases the WebDB.config file will be updated with the corresponding file when you build.
NOTE: make sure you set the webdb.config, webdb.debug.config, and webdb.release.config to "Do not copy" for the "Copy to Output Directory" option.
Hope this helps!
I have been using SlowCheetah but I found something that I think is more elegant. Just telling to the build to generate the .config depending on the build configuration.
Having a app.Release.config in your project (or many more depending on you deployment needs) you just need to edit the project file (the .csproj one if you program in C#). Find the end of it, between the last </ItemGroup> and </Project> and add:
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
<PropertyGroup>
<OutputTypeName>$(OutputType)</OutputTypeName>
<OutputTypeName Condition="'$(OutputTypeName)'=='Library'">dll</OutputTypeName>
<OutputTypeName Condition="'$(OutputTypeName)'=='Module'">dll</OutputTypeName>
<OutputTypeName Condition="'$(OutputTypeName)'=='Winexe'">exe</OutputTypeName>
</PropertyGroup>
<TransformXml Source="Config\app.config" Transform="Config\app.$(Configuration).config" Destination="$(OutputPath)\$(AssemblyName).$(OutputTypeName).config" />
</Target>
</Project>
Save and reload from VisualStudio. Compile in Release mode and check the bin/Release folder on your <MyProject>.config file the transformation is done.
This example applies to Exe and Dll files and any VisualStudio version because includes this post help
There is another approach that doesn't require installing extensions nor using build events.
Let's suppose you have your custom configs like so:
myConfig.config
myConfig.Uat.config
myConfig.Release.config
Then in your main Web.config you have this:
<mySection configSource="myConfig.config" />
Lastly, inside your Web.Uat.config you add a transform like this:
<mySection configSource="myConfig.Uat.config" xdt:Transform="SetAttributes" />
This is not transforming the myConfig.config file, but rather overriding the name of the custom config file that should be used. You can do the same for the Release and any other environments.
Your myConfig.Uat.config should not contain transformations, it should be a copy of the base custom config file, with the appropriate values for the custom environment.
The downside is everytime you add something to the base custom config file, you need to also add to the config files for other envs (even if the value should be the same through envs). So I'd consider just using these custom config files for settings that should be changed between envs.
I had a similar need to transform a custom config file, but in a class library. Andoni Ripoll Jarauta's solution worked when I built the project directly, but when I built another project that referenced it the transformed file would not get copied. I found that in addition I had to add the transformed file to AssignTargetPathsDependsOn for that to happen. This did the trick:
<PropertyGroup>
<AssignTargetPathsDependsOn>
$(AssignTargetPathsDependsOn);
BuildCustomConfig;
</AssignTargetPathsDependsOn>
</PropertyGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="BuildCustomConfig">
<TransformXml Source="MyCustom.config" Transform="MyCustom.$(Configuration).config" Destination="$(OutputPath)\MyCustom.config" />
<ItemGroup>
<Content Include="$(OutputPath)\MyCustom.config" Condition="Exists('$(OutputPath)\MyCustom.config')">
<Link>MyCustom.config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Target>
Since the OP asked about Web.config transformations during the deployment lets assume the WPP is already in there. So I've hacked on the WPP.
I use the following snippet to transform Umbraco's own config files (but indeed any configs suit well):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<UmbracoConfigsToTransform Include="Config\umbracoSettings.config">
<DestinationRelativePath>Config\umbracoSettings.config</DestinationRelativePath>
</UmbracoConfigsToTransform>
</ItemGroup>
<PropertyGroup>
<CollectWebConfigsToTransformDependsOn>
$(CollectWebConfigsToTransformDependsOn);
CollectUmbracoConfigsToTransform
</CollectWebConfigsToTransformDependsOn>
</PropertyGroup>
<Target Name="CollectUmbracoConfigsToTransform">
<!-- The logic comes from the 'CollectWebConfigsToTransform' task -->
<ItemGroup>
<WebConfigsToTransform Include="#(UmbracoConfigsToTransform)">
<Exclude>false</Exclude>
<TransformFile>$([System.String]::new($(WebPublishPipelineProjectDirectory)\$([System.IO.Path]::GetDirectoryName($([System.String]::new(%(DestinationRelativePath)))))).TrimEnd('\'))\%(Filename).$(Configuration)%(Extension)</TransformFile>
<TransformOriginalFolder>$(TransformWebConfigIntermediateLocation)\original</TransformOriginalFolder>
<TransformFileFolder>$(TransformWebConfigIntermediateLocation)\assist</TransformFileFolder>
<TransformOutputFile>$(TransformWebConfigIntermediateLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
<TransformScope>$([System.IO.Path]::GetFullPath($(WPPAllFilesInSingleFolder)\%(DestinationRelativePath)))</TransformScope>
</WebConfigsToTransform>
</ItemGroup>
</Target>
</Project>
I name it Umbraco.wpp.targets and drop inside project's root. Then the WPP automatically imports it.
All you have then to do is add a transform file (Config\umbracoSettings.Release.config in case of this sample).