Deploying .NET Core app using a custom Kudu script

Deploying .NET Core app using a custom Kudu script

With the recent release of .NET Core 3 and the even more recent announcement of .NET Core 3.1 LTS, I felt now was a good time to move iambacon blog over from the .NET framework to the new world of .NET.

As part of the update, I wanted to separate the CMS from the blog. iambacon is an MVC web app and the CMS part of it was an Area within the app. I'm not a fan of Areas, I don't have a good argument against them, I used Areas in this app to see if it would change my mind, it didn't. So I've created a new ASP.NET Core web app and migrated the CMS to that.

Azure deployment

I deploy my blog to Azure using Git. It is simple and straightforward. I have a custom Kudu deployment script as I also compile Sass and run unit tests. I'm very happy with it and do not feel the need to change to say Azure DevOps.

Deploying a .NET Core app

There is a custom deployment script generator for Kudu called Kudu Script, which will generate a script for you. The example given on the wiki page is

kuduscript -y --aspWAP pathToYourWebProjectFile.csproj -s pathToYourSolutionFile.sln

There are two options:

  • --aspWAP: ASP.NET web application (path to the .csproj file)
  • -s: path to the .sln file

This will create a deploy.cmd script with the following for the CMS app.

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

echo Handling .NET Web Application deployment.

:: 1. Restore NuGet packages
IF /I "src\IAmBacon\IAmBacon.sln" NEQ "" (
  call :ExecuteCmd nuget restore "%DEPLOYMENT_SOURCE%\src\IAmBacon\IAmBacon.sln"
  IF !ERRORLEVEL! NEQ 0 goto error
)

:: 2. Build to the temporary path
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\src\IAmBacon\IAmBacon.Admin\IAmBacon.Admin.csproj" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="%DEPLOYMENT_TEMP%";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release;UseSharedCompilation=false /p:SolutionDir="%DEPLOYMENT_SOURCE%\src\IAmBacon\\" %SCM_BUILD_ARGS%
) ELSE (
  call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\src\IAmBacon\IAmBacon.Admin\IAmBacon.Admin.csproj" /nologo /verbosity:m /t:Build /p:AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release;UseSharedCompilation=false /p:SolutionDir="%DEPLOYMENT_SOURCE%\src\IAmBacon\\" %SCM_BUILD_ARGS%
)

IF !ERRORLEVEL! NEQ 0 goto error

:: 3. KuduSync
IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
  call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
  IF !ERRORLEVEL! NEQ 0 goto error
)

Running the script will fail with this error:

error MSB4041: The default XML namespace o f the project must be the MSBuild XML namespace. If the project is authored in the MSBuild 2003 format, please add xmln s="http://schemas.microsoft.com/developer/msbuild/2003" to the element. If the project has been authored in t he old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.

This because Kudu Script has generated a script for a .NET web application, not a .NET Core web application.

Unfortunately the example in the wiki is for the old .NET apps and does not mention .NET Core at all.

Generating the right script

Run kuduscript --help to get the list of options.

There are several options the one we’re interested in is

--aspNetCore <projectFilePath>      Create a deployment script for ASP.NET Core web application, specify the project file path

Swap --aspWAP for --aspNetCore.

kuduscript -y --aspNetCore pathToYourWebProjectFile.csproj -s pathToYourSolutionFile.sln

This time the deployment script will contain

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Deployment
:: ----------

echo Handling ASP.NET Core Web Application deployment.

:: 1. Restore nuget packages
call :ExecuteCmd dotnet restore "%DEPLOYMENT_SOURCE%\src\IAmBacon\IAmBacon.sln"
IF !ERRORLEVEL! NEQ 0 goto error

:: 2. Build and publish
call :ExecuteCmd dotnet publish "%DEPLOYMENT_SOURCE%\src\IAmBacon\IAmBacon.Admin\IAmBacon.Admin.csproj" --output "%DEPLOYMENT_TEMP%" --configuration Release
IF !ERRORLEVEL! NEQ 0 goto error

:: 3. KuduSync
call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
IF !ERRORLEVEL! NEQ 0 goto error

Running the script will build and publish successfully.

Summary

Kudu is a simple way to deploy apps to Azure using Git. Kudu allows custom deployment scripts which are simple to generate however using the correct options is essential. It's a shame the wiki does not give a .NET Core example but hopefully this article has helped fill in the blanks.