Friday, July 15, 2022

How to Successfully Deploy .NET Web App Built with Windows Agent Using Linux Agents

 

When building a .NET Web App with /p:WebPublishMethod=Package build argument to package as a web deployment package, the package is created with a folder structure where all the dll files are located in inner subfolder. If we use Azure DevOps Windows agents, We can deploy these packages using msdeploy.exe to correct path of Azure App service without worrying about the folder structure of the build package. However, If we use Azure DevOps Linux agents to deploy, it deploys packages with kudus copy and copying the inner folder structure  to wwwroot. Then the App service will fail to run the .NET web application. This blog explains how to correctly deploy a .NET Web App built with Windows as a web deployment package using Azure DevOps Linux agents.

Web deployment package would create a folder hierarchy such as below. If we deploy below package using Linux agent, it will copy content folder with the all the sub folders to the wwwroot of the App service making the app to not runnable.


As a fix to the Linux deployment issue, We can add a new step to build pipeline which extract the published artifact package, correct the folder structure and compress to create build artifact package with correct folder structure.

Add following PowerShell script to build pipeline after Visual Studio build step which is packaging the project as a web deployment package. This PowerShell script can be used with a solution with multiple projects using dotnetcore 3.1, web APIs, webjobs and .NET framework web jobs. You might have to add additional path searches to support other .NET core versions and project types. You can extract the relevant web deploy packages to identify the path filters and modify $publishFolderPath = Get-ChildItem $extractPath -Directory -Recurse | Where-Object { $_.FullName.EndsWith('\netcoreapp3.1\PubTmp\Out') -or $_.FullName.EndsWith('\netcoreapp3.1\Package\PackageTmp') -or $_.FullName.EndsWith('\x64\Release\Package\PackageTmp') } accordingly.

$rootPath = '$(build.artifactstagingdirectory)';
Add-Type -assembly "system.io.compression.filesystem"
$zipFiles = Get-ChildItem $rootPath -Filter *.zip
$extractPath = -join ($rootPath, "\1");
foreach ($zipFile in $zipFiles) {
   write-host $zipFile.FullName
   Expand-Archive -Path $zipFile.FullName -DestinationPath $extractPath -Force
   $publishFolderPath = Get-ChildItem $extractPath -Directory -Recurse | Where-Object { $_.FullName.EndsWith('\netcoreapp3.1\PubTmp\Out') -or $_.FullName.EndsWith('\netcoreapp3.1\Package\PackageTmp') -or $_.FullName.EndsWith('\x64\Release\Package\PackageTmp') }
   Remove-Item -Path $zipFile.FullName -Force
   [io.compression.zipfile]::CreateFromDirectory($publishFolderPath.FullName, $zipFile.FullName)
   Remove-Item -Path $extractPath -Recurse -Force
}


No comments:

Post a Comment