DEV Community

Cover image for Nuke: Deploy ASP. NET Web App to Azure
Raul Naupari
Raul Naupari

Posted on • Originally published at blog.raulnq.com

Nuke: Deploy ASP. NET Web App to Azure

In this post, we will explore the benefits of Nuke and its most common features as we deploy a web app to Azure. Our goal is to achieve a flexible, maintainable, automated build process.

Nuke is an open source, cross-platform build automation solution for .NET projects. Nuke prides itself on its simplicity and extensibility that makes build automation approachable for everyone.

Today, tools like Continuous Integration Servers perform the same job. So, why should we move the build process from CI Servers to Nuke and use them as simple runners?

  • Reduce Vendor Lock-In: Switching from one CI platform to another requires a significant effort.

  • Democratize DevOps: If something breaks or a developer adds a feature that needs changes in the build process, progress halts until the build manager is available.

  • Reduce Mismatch: Occasionally, a change affects the code and the build process. When you move the feature to the development branch, you must to remember to update the related build process.

  • Simplify Debugging: When things go wrong on a CI server with custom logic, you can't set breakpoints, you can't access environmental differences, logging options are limited, and you often have to wait a long time to see the results of any changes.

Concepts

Target

A target is something that must happen. A collection of targets defines your build process. They are similar to the build steps in your CI server.

Target Restore => _ => _ .Executes(() => { DotNetRestore(s => s .SetProjectFile(Solution)); }); 
Enter fullscreen mode Exit fullscreen mode

Parameters

A parameter is a value provided by the command line.

[Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; 
Enter fullscreen mode Exit fullscreen mode

Dependencies

A dependency specifies which targets need to run first.

Target Compile => _ => _ .DependsOn(Restore) .Executes(() => { DotNetBuild(s => s .SetProjectFile(Solution) .SetConfiguration(Configuration) .EnableNoRestore()); }); 
Enter fullscreen mode Exit fullscreen mode

Code

Let's start by installing Nuke:

dotnet tool install Nuke.GlobalTool --global 
Enter fullscreen mode Exit fullscreen mode

Then, in the same directory as your solution, run:

 nuke :setup 
Enter fullscreen mode Exit fullscreen mode

Nuke will start asking questions to set up your build project:

NUKE Global Tool version 6.0.1 (Windows,.NETCoreApp,Version=v3.1) How should the build project be named? ¬ _build Where should the build project be located? ¬ ./build Which NUKE version should be used? ¬ 6.0.3 (latest release) Which solution should be the default? ¬ nuke-sandbox-app.sln Do you need help getting started with a basic build? ¬ No, I can do this myself... 
Enter fullscreen mode Exit fullscreen mode

At this point, Nuke will add a new project named _build to your solution. Find the Build.cs file and open it. Add the following namespaces to access all dotnet commands:

using Nuke.Common.Tools.DotNet; using static Nuke.Common.Tools.DotNet.DotNetTasks; 
Enter fullscreen mode Exit fullscreen mode

Delete all the targets and replace them with the following code:

Target Restore => _ => _ .Executes(() => { DotNetRestore(s => s .SetProjectFile(Solution)); }); Target Compile => _ => _ .DependsOn(Restore) .Executes(() => { DotNetBuild(s => s .SetProjectFile(Solution) .SetConfiguration(Configuration) .EnableNoRestore()); }); 
Enter fullscreen mode Exit fullscreen mode

Open a console in the same directory as your solution and run:

nuke Compile 
Enter fullscreen mode Exit fullscreen mode
╬════════════  Restore ╬═══  09:23:21 [INF] > "C:\Program Files\dotnet\dotnet.exe" restore D:\Source\Github\nuke-sandbox\nuke-sandbox-app.sln 09:23:21 [DBG] Determining projects to restore... 09:23:22 [DBG] Restored D:\Source\Github\nuke-sandbox\nuke-sandbox-app\nuke-sandbox-app.csproj (in 87 ms).  ╬════════════  Compile ╬═══  09:23:22 [INF] > "C:\Program Files\dotnet\dotnet.exe" build D:\Source\Github\nuke-sandbox\nuke-sandbox-app.sln --configuration Debug --no-restore 09:23:22 [DBG] Microsoft (R) Build Engine version 17.1.0+ae57d105c for .NET 09:23:22 [DBG] Copyright (C) Microsoft Corporation. All rights reserved. 09:23:22 [DBG] 09:23:25 [DBG] nuke-sandbox-app -> D:\Source\Github\nuke-sandbox\nuke-sandbox-app\bin\Debug\net6.0\nuke-sandbox-app.dll 09:23:26 [DBG] 09:23:26 [DBG] Build succeeded. 09:23:26 [DBG] 0 Warning(s) 09:23:26 [DBG] 0 Error(s) 09:23:26 [DBG] 09:23:26 [DBG] Time Elapsed 00:00:03.33  ═══════════════════════════════════════ Target             Status      Duration ─────────────────────────────────────── Restore            Succeeded     < 1sec Compile            Succeeded       0:03 ─────────────────────────────────────── Total                              0:04 ═══════════════════════════════════════ 
Enter fullscreen mode Exit fullscreen mode

Congratulations, you are compiling your solution with Nuke. To deploy the web app to Azure, we will use the Kudu's zip API. We must create a target to run the dotnet publish command and another to zip the results. Add two AbsolutePath variables to store the results of these commands:

AbsolutePath OutputDirectory => RootDirectory / "output"; AbsolutePath ArtifactDirectory => RootDirectory / "artifact"; 
Enter fullscreen mode Exit fullscreen mode

And add the following targets:

Target Clean => _ => _ .Before(Restore) .Executes(() => { EnsureCleanDirectory(OutputDirectory); EnsureCleanDirectory(ArtifactDirectory); }); Target Publish => _ => _ .DependsOn(Compile) .DependsOn(Clean) .Executes(() => { DotNetPublish(s => s .SetProject(Solution) .SetConfiguration(Configuration) .SetOutput(OutputDirectory) .EnableNoRestore() .SetNoBuild(true)); }); Target Zip => _ => _ .DependsOn(Publish) .Executes(() => { ZipFile.CreateFromDirectory(OutputDirectory, ArtifactDirectory / "deployment.zip"); }); 
Enter fullscreen mode Exit fullscreen mode

Run the nuke command and check the output and artifact folders:

nuke Zip 
Enter fullscreen mode Exit fullscreen mode

Let's move to the final step and add three parameters:

[Parameter()] public string WebAppUser; [Parameter()] public string WebAppPassword; [Parameter] public string WebAppName; 
Enter fullscreen mode Exit fullscreen mode

And copy this target:

Target Deploy => _ => _ .DependsOn(Zip) .Requires(() => WebAppUser) .Requires(() => WebAppPassword) .Requires(() => WebAppName) .Executes(async () => { var base64Auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{WebAppUser}:{WebAppPassword}")); using (var memStream = new MemoryStream(File.ReadAllBytes(ArtifactDirectory / "deployment.zip"))) { memStream.Position = 0; var content = new StreamContent(memStream); var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", base64Auth); var requestUrl = $"https://{WebAppName}.scm.azurewebsites.net/api/zipdeploy"; var response = await httpClient.PostAsync(requestUrl, content); if (!response.IsSuccessStatusCode) { Assert.Fail("Deployment returned status code: " + response.StatusCode); } } }); 
Enter fullscreen mode Exit fullscreen mode

To get the user and password, go to the Azure portal and find the Deployment Center option:

Image description

For the user, use the last part after the backslash. Run the help command to see all the available options:

nuke --help 
Enter fullscreen mode Exit fullscreen mode
NUKE Execution Engine version 6.0.3 (Windows,.NETCoreApp,Version=v6.0)  Targets (with their direct dependencies): Restore Compile (default) -> Restore Clean Publish -> Compile, Clean Zip -> Publish Deploy -> Zip Parameters: --configuration Configuration to build - Default is 'Debug' (local) or 'Release' (server). --web-app-password <no description> --web-app-user <no description> --web-app-name <no description> --continue Indicates to continue a previously failed build attempt. --help Shows the help text for this build assembly. --host Host for execution. Default is 'automatic'. --no-logo Disables displaying the NUKE logo. --plan Shows the execution plan (HTML). --profile Defines the profiles to load. --root Root directory during build execution. --skip List of targets to be skipped. Empty list skips all dependencies. --target List of targets to be invoked. Default is 'Compile'. --verbosity Logging verbosity during build execution. Default is 'Normal'. 
Enter fullscreen mode Exit fullscreen mode

Run the following command:

nuke Deploy --web-app-password <pasword> --web-app-name nuke-sandbox-app --web-app-user '$nuke-sandbox-app' 
Enter fullscreen mode Exit fullscreen mode

Go to your site to see the web app running. Finally, to see your build process in a nice dependency graph, run the following command:

nuke --plan 
Enter fullscreen mode Exit fullscreen mode

Image description

You can find the solution here. Thank you, and happy coding.

Top comments (0)