Azure DevOps - How to Publish an ASP.NET application - asp.net

I have an ASP.NET (4.7.2) app that successfully runs and starts on my machine. This app has a web.config file that contains the following:
Web.config
<appSettings>
<add key="username" value="someone#email.com" />
<add key="port" value="25" />
</appSettings>
These are the configuration values I want to use while working. However, when I deploy the app to my Azure App Service for test purposes, I want to change the port value. For that reason, I've added a config transform named "Web.Test.config" with the following:
Web.Test.config
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="port" value="58" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
</configuration>
Unfortunately, it doesn't seem like the transform is happening. I've ready that the transforms only happen during "publishing". At this time, I'm deploying via an Azure DevOps Pipeline that includes the following tasks:
NuGet
Restores the packages based on the .sln file
MSBuild
Builds the .csproj that defines my ASP.NET app. The "Configuration" property is set to "Test".
Azure App Service Deploy
Attempts to deploy the ASP.NET app as a "Web App on Windows" to my deployment slot. The "Package or folder" is set to MyAspNetApp. The
While this build pipeline successfully runs, the configuration transforms do not seem to be taking effect. How do I do a "publish" via an Azure DevOps Build Pipeline to an Azure App Service so that my config transformations will be generated.

For App.Config or Web.Config (XML) file there are two options.
File Transform task suggested by #Jabberwocky in the comment.
Variable Substitution as per below image in the release pipeline.
Sample XML variable substitution
For modern .NET apps where we use json configuration, variable substitution is the only way. Even though File Transform task promises to work for both it is not clear as per this thread
For JSON variables, you have to enter the full path hierarchy like this
Sample JSON variable substitution

How do I do a "publish" via an Azure DevOps Build Pipeline to an Azure App Service so that my config transformations will be generated.
First, we need to make sure the web.*.config files are included in the build output and the file is transformed correctly. Check it locally first.
Besides, the following steps should help:
Remove the nesting of the web.dev/stest/atest/prod.config files
either by removing the element in csproj, a nesting
add-on for VS or the File Nesting context menu item in VS 2017
A note from the documentation stated XML transformation notes that:
By default, MSBuild applies the transformation as it generates the web
package if the element is already present in the
transform file in the *.csproj file. In such cases, the Azure App
Service Deploy task will fail because there is no further
transformation applied on the Web.config file. Therefore, it is
recommended that the element is removed from all the
transform files to disable any build-time configuration when using XML
transformation.
Make sure that the *.config files have the 'Copy to Output Directory'
property set to if newer or always
Build the solution locally and check the contents of bin\release
folder and make sure the web.*.config files are included
Run a build in VSTS and make sure the web.*.config files are included
in the zipped package
Check the checkbox XML transformation on the Azure App Service Deploy task:
There is a great document about how to Using XML Transformations when deploying to Azure App Service using VSTS, you can check it for some more details.
BTW, since you just need to change the port value, you can use the option XML variable substitution on the the Azure App Service Deploy task.
Ticket for details: How to transform Web.Config file 'Properly' with VSTS!
Hope this helps.

Related

How to Setup and Deploy a .net web app Build Using TFS 2015.Update3.RC1 CI on Prim

Using Visual Studio 2015 update 3
and Team Foundation server Update 3 (on-site)
I'm attempting to setup up and auto deploy for a .net core boilerplate app targeting full framework 4.61. Currently my app is mostly the stock app you get when selecting new->Project->Templates->Visual C#->Web->ASP.NET Core Web Application(.Net Framework). My Goal is to Push via Git and then have the website show up correctly on the test server.
I was able to use the instructions I found at the MVA
However, they did not go into any detail on how to deploy to an on-prem server. But they clearly stated that it was possible.
I have Setup this web project in TFS2015 using Git as source control. For my Build Definition I'M using the Visual Studio default build ScreenShot of TFS build Definition, I also have the site building whenever I push new code.
The problem I have is I don't understand what to do next.
my thought is that I would need to:
turn off IIS (iisreset -stop) via PowerShell.
Move the built files to my iss location. In this example, it is C:\inetpub\apps\My
run scripts to update database schema(note currently there is no database setup but that is my next step. planning to use "code first" with "Entity Framework"
I would have to turn IIS back on.
I did get a big clue to add the following in my Visual Studio Build Step. MSBuild Arguments.
/p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish
/p:WebPublishMethod=FileSystem /p:DeleteExistingFiles=True
/p:publishUrl=$(build.artifactstagingdirectory)\for-deploy\website
From Benjamin Day Blog www.benday.com/2016/09/08/an-asp-net-mvc-site-thats-easy-to-deploy-from-a-tfs-build/ (sorry can't link due to lack of rep points)
using those build MS build arguments I can find my built website and it appears to be working correctly except for the Web.config file is showing
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
When is should be
<aspNetCore processPath=".\My.Multnomah.exe" arguments="" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />
My Release Definition is in three steps
PowerShell on Target Machines
Machines = the server I'm going to deploy to
Admin Login = My AD username.(will switch to service account after working)
Protocol = Https
PowerShell Script = file location on the Script I have on the agent PC/which is also the test web server
here is the PowerShell script to turn of IIS.
iisreset -stop
Windows Machine File Copy
this step is working correctly
PowerShell on Target Machines
same as step 1. but
Currently, the Release is working if I manually turn off IIS then manually update the web.config file.
So, in short here are the questions?
How can I automatically Correct the web.config?
How can I arrange to have IIS Stopped before the file transfer and Started after the Transfer or is there a better way?(Current the release is failing if I don't have IIS off)
Is my understanding how I explained this correct/ What are the Build steps you would use to deploy on-prem?
1.How can I automatically Correct the web.config?
You can replace corresponding values with variable values (Open your build definition=>Variable) by using Replace Token task.
For example: Add variables to your build/release definition (e.g. name:LAUNCHER_PATH value:.\My.Multnomah.exe), change your web.config (replace %LAUNCHER_PATH% to #{LAUNCHER_PATH}# and others)
2.How can I arrange to have IIS Stopped before the file transfer and Started after the Transfer or is there a better way?
You don’t need to stop IIS before update web.config file, you can update it directly. After updating web.config, the website will be recycled automatically.
3.Is my understanding how I explained this correct/ What are the Build steps you would use to deploy on-prem?
These steps are ok, there are IIS Web App Deployment Using WinRM and IIS Utilities task that can help you to deal with IIS.

Why need web.debug.config?

When build and run in VS, VS won't do web.config transformation, IISExpress always reads and uses web.config. Web.config transformation only happens when deploy.
Then why we need web.debug.config? We can add set all debug purpose properties in web.config directly, like <compilation debug="true">, then override those properties in web.release.config when do deployment. The whole process looks like it doesn't need web.debug.config at all.
Does anyone know why we need web.debug.config? Someone may say when we want to deploy debug build to web server, well, if that is the case it can also done by direct copy web.config to web server.
these files are added by default based on your default build configurations (Release and Debug). Acutally you can freely delete this file assuming that every publish and deploy to environment different than dev should be in Release mode.

How to include app pool specification in asp.net deploy script?

I have an MSBuild script that is generating a deployment script for my web app.
Project.build (excerpt)
<MSBuild Projects="xxxxx.sln" Properties="
CreatePackageOnPublish=true;
DeployOnBuild=true;
IncludeIisSettings=true;
IncludeAppPool=true;" >
<Output TaskParameter="TargetOutputs" ItemName="CompiledAssembly" />
</MSBuild>
When this is executed, it does produce a Package folder in the output that contains a deployment .cmd file and associated .zip file.
xxxx.SetParameters.xml (generated)
<?xml version="1.0" encoding="utf-8"?>
<parameters>
<setParameter name="IIS Web Application Name" value="Default Web Site\xxxxx" />
<setParameter name="DefaultConnection-Web.config Connection String"
value=" ... snipped ..." />
</parameters>
As you can see, there is no reference to app pool here. Likewise, there is mention of app pool in the generated xxxx.zip\parameters.xml
When I execute xxxxxx.deploy.cmd /Y, it correctly creates the application in IIS. The problem is, it seems to use the default application pool for the machine. It's a .net 4 app, so if the default is .net 2, the app fails to run.
Is there a way to make the deployment script include an app pool definition so that it won't require manual app pool changes to run?
I did find this question, which seems to be the same. However, as you can see, I've already included the answer from that question, and it has no effect.
If you're trying to deploy a 4.0 app to a 2.0 default app pool without providing an override it will not fail to run but fail to deploy, MSDeploy would simply fail to precreate a virtual app with ERROR_APPPOOL_VERSION_MISMATCH error.
IncludeAppPool is the correct property, but it only tells the packager to include the settings, you have to provide the source, i.e. the "master" virtual app with correct app pool to copy from.
Open project properties and switch from IIS Express to Local IIS, this will enable app pool flag under the package/publish options. I believe you can switch back afterwards, the settings will remain.
This would basically do 2 things, add <IncludeAppPool>true</IncludeAppPool> as well as add the master app under <WebProjectProperties> section. Now when you build or package your source manifest will not have the managedRuntimeVersion requirement but your parameters will now have IIS Web Application Pool Name to customize.
If you want to actually create a new app pool then it gets tricky. I'm not aware of a way to create it during iisApp creation or with some MSBuild flag, but with MSDeploy (the tool behind your .cmd) it would require a dump of your local pool and sync up with appPoolConfig provider, probably as part of your .build script before the .cmd call.
msdeploy -verb:sync -source:appPoolConfig=Foo -dest:package=foo.zip
msdeploy -verb:sync -source:package=foo.zip -dest:appPoolConfig=Foo,computerName=Bar
Keep in mind that without specifying individual appPoolConfig the sync, as it should, would destroy other pools, so do -whatIf first just in case.
You can probably try to merge the archive.xml of your package and the archive.xml with the app pool definition, but I can't image how it would work and what relationship between iisApp and appPoolConfig providers is there.
Edit: You can use manifest provider to combine package or iisApp with appPoolConfig

Web.config Build vs Release transform not working

I have an ASP.NET Web Application project that connects to a remote database via the Entity Framework. During debugging (eg running the project on my local computer), the IP address to the database is different than during release (eg after uploading the project to my webserver and running it from the browser). Until now I have always manually changed the database connection string in the Web.config file to switch between the two (basically I had to connection strings, one named 'Debug' and one 'Release' and I just swapped around the names whenever I deployed).
Now I just noticed that it should be possible to let this happen automatically via the Web.config Transformation Syntax where you put the modified connection string in the Web.Release.config version and it should then use that when the DLL is built under Release configuration.
However it does not seem to work for me...
Here is the relevant part of my regular Web.config file (which holds the Debug connection string for local usage):
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<!-- Debug connection string. Release connection string is in Web.Release.config file -->
<add name="DatabaseEntities" connectionString="A" providerName="System.Data.EntityClient" />
</connectionStrings>
</configuration>
Here is the Web.Release.config file, which according to the examples should replace the 'DatabaseEntities' connection string "A" with "B" if the DLL is under Release mode:
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!-- Replace the DatabaseEntities connection string with the Release version (local IP address) -->
<connectionStrings>
<add name="DatabaseEntities"
connectionString="B"
xdt:Transform="Replace" xdt:Locator="Match(name)"/>
</connectionStrings>
</configuration>
(Obviously "A" and "B" are just place-holders for my real connection strings)
When I debug the application (e.g. just press F5) the default Web.config is used and I can access the database. I then change the build configuration to Release via the Configuration Manager. All the projects in the solution are set to Release configuration. Then I Build the solution (just via Build or even via a complete rebuild (e.g. Clean, Rebuild)). I upload the newly built DLLs to the webserver, as well as the Web.config and Web.Release.config files, and when I try to access the database I am unable, it is still trying to access the database via the debug IP address and hence cannot find it...
It seems the Web.Release.config file is completely ignored, or at least the connection string is not being replaced.
What am I doing wrong? Is the transformation syntax wrong? Am I not building the application under Release mode correctly?
Then I Build the solution (just via Build or even via a complete
rebuild (e.g. Clean, Rebuild)). I upload the newly built DLLs to the
webserver, as well as the Web.config and Web.Release.config files
There is your error: Web config transforms won't work for your local environment, if you simply build. You need to publish.
Your deployment process seems weird: You are only copying DLLs, Web.config and web.Release.config. To me it seems, that you copy your source code and not a compiled application. A published WebApplication doesn't contain a web.release.config.
You should publish your project (rightclick on your WebApplication -> Publish) to your local filesystem and copy the files from there, or use another deployment method of your choice.
2 years ago I wrote an article about web.config transforms. It gives you a step-by-step tutorial for VS 2010 (The publish dialog changed in VS 2012): http://www.tomot.de/en-us/article/5/asp.net/how-to-use-web.config-transforms-to-replace-appsettings-and-connectionstrings
Inside your csproj file, you can add an action to execute before every build and perform the web.config transformations:
<Target Name="BeforeBuild">
<TransformXml Source="web.config" Transform="web.$(Configuration).config" Destination="web.config" />
</Target>
You can try the Slow Cheetah plugin:
http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5
This will let you see the transformations 'live' by giving you an extra context menu option. Right-click and choose Preview Transform to see the transformation without having to do a build. Its also really handy for implementing app.config transformations
I thought transformation is only done when you publish the site/app.
It is not done when building an application. The latter would constantly change the web.config under source control (which would be a real hassle)
If it's only connections strings that are not overwritten during web.config transformation, then this is what I did:
I cleared the "Use this connection string at runtime" check-box in the "Settings" section of "Publish Web" wizard. This setting was overwriting web.config transformation of the connection string.
It's pretty flexible, you should be able to make a few tweaks to apply custom transforms on build (and without having to publish)
We implemented this in our (Windows Service) project, applying transforms on build
You will need to modify your project file and add something similar to below
Here we're telling msbuild to apply transform after finish compiling, but only if condition is true (see https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions?view=vs-2017)
Notice we are using an build prop (self defined msbuild prop) "Env", e.g. msbuild ... /p:Env=Prod would result in App.Prod.config
<UsingTask TaskName="TransformXml" AssemblyFile="C:\Some\Path\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterCompile" Condition="Exists('some condition')">
<!--Generate transformed app config in the intermediate directory-->
<TransformXml Source="App.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="App.$(Env).config" />
<!--Force build process to use the transformed configuration file from now on.-->
<ItemGroup>
<AppConfigWithTargetPath Remove="App.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>

ASP.NET Web.config transformation won't work in installer

I am working on an ASP.NET project in Visual Studio .NET 2010 and attempting to make an MSI installer using a Web Setup Project. I added the Primary output from the project (which seems to pull in the relevant dependencies) and the Content Files from the project (which pulls in the Web.config and the .svc files).
The issue is that rather than applying the XDT transform and creating the Web.config using the Web.Release.config, it just copies the Web.config, the Web.Release.config, and the Web.Debug.config into the installer without doing any transformation at all.
How do I get it to apply the Web.config transformation before creating the installer?
I found a workaround that works for me:
Create needed configurations (Dev,QA,Production etc.) and associated web config transformations.
Use notepad or other text editor and include following in your web application project file (.csproj file) before tag (near the end of the project file):
<Target Name="AfterBuild">
<TransformXml Source="Web.config" Transform="$(ProjectConfigTransformFileName)" Destination="Web.Transformed.config" />
</Target>
Do not include Web.Transformed.config in the web application project - if you do visual studio will alert you about the changes after every build which is pretty annoying.
In the web setup project:
select Content files - > Exclude Filter and add Web.config (and all other Web.*.config files containing transformation rules).
In the web setup project:
select file system editor icon -> web application folder -> Add File
and select Web.Transformed.config in the root of your web application project folder.
In the same screen: right click Web.Transformed.config and rename it to Web.config
Now you are able to generate .msi files with selected configuration and root web.config file is transformed!
Please note that this does not affect web.config files in the sub folders.
The answer ended up being located on another SO post which I missed when I was searching through before asking because it wasn't exactly what I wanted:
MSBuild Script and VS2010 publish apply Web.config Transform
A co-worker suggested using that to place the transformed Web.config in the project's bin directory and a Web Setup Project configured to grab the Web.config out of the bin directory and put it in the installer. This ended up being the most workable solution without installing any add-ons into Visual Studio.
You have to make a deployment project (I think this is a separate download), then your Web Setup project take the precompiled output of the deployment project as it input. One neat thing is that you can have it change a section of your Web.config when it builds.

Resources