Gotchas when deploying a WebJob to Azure.
Tags: webdev, devops, dotnet, azure
Published: 2020-02-05 18:41:28

---
title: Gotchas when deploying a WebJob to Azure.
published: true
description: Azure App Services - Deploying a .NET Core 3.1 worker as a schedule triggered WebJob via DevOps
tags: webdev,devops,dotnet,azure
---


# Azure App Services - Deploying a .NET Core 3.1 worker as a schedule triggered WebJob via DevOps

This article will cover some issues I ran into creating a new .NET Core 3.1 worker as a scheduled triggered WebJob on Azure App Services (AAS)

You might need to be a little familiar with: .NET Core, Azure DevOps, AAS, Kudu.

## Goals

Lean into conventions as much as possible. Avoid complicated customization to the pipelines YAML, or deployment pipeline or unnecessary extra scripts and files in the repo.

## Getting Started

### Environment

- Create the AAS as Windows only because WebJobs are not yet available on Linux.
- Enable Always-On (so the scheduler works). You may see Core 3.1 Runtime is not on the Windows AAS according to the Azure Portal GUI but it actually is. 

### Pipeline

Creating the app from scratch is easy: `dotnet new worker --name MyFirst.Worker`

Create a very basic .NET Core azure-pipeline.yaml, all it needs to do is run the core publish task and then publish the artifact. The core template for DevOps does this out of the box.

Use this guide: [https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/dotnet-core?view=azure-devops](https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/dotnet-core?view=azure-devops)

```yaml
steps:

# ...

- task: DotNetCoreCLI@2
  inputs:
    command: publish
    publishWebProjects: True
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
    zipAfterPublish: True

# this code takes all the files in $(Build.ArtifactStagingDirectory) and uploads them as an artifact of your build.
- task: PublishBuildArtifacts@1
  inputs:
    pathtoPublish: '$(Build.ArtifactStagingDirectory)' 
    artifactName: 'MyFirstWorker'
```

Run the build and verify your worker was published.
  

### First gotcha:

Always generate an Exe. Kudu looks for specific files to run. If you use the DevOps Ubuntu agent, you wont get an Exe. So how can we ALWAYS get one? 

**You need to edit the publish arguments in your pipeline YAML and add `-r win-x86 --self-contained false`.** this will force Core to spit out an Exe for windows, even when publishing on Ubuntu. WITHOUT creating a self contained deployment. Although, there is nothing wrong with creating an SCD if you want. might even be a good idea, but for this tutorial I want to go from `dotnet new` to a working deployment without lighting up every feature in Core and without adding more scripts and files to my repo.

NOTE: To see how Kudu picks something to run, check the Wiki for WebJobs[Kudu wiki](https://github.com/projectkudu/kudu/wiki/WebJobs).

### Second gotcha:

The path you deploy to in AAS for web jobs is highly specific. It MUST be in one of the following:

For a triggered (or scheduled) job, the folder is `wwwroot\app_data\jobs\triggered\{job name}`, and for a continuous job, it's `wwwroot\app_data\jobs\continuous\{job name}`. **This is easily achieved by setting the `--output` flag on your `dotnet publish` to publish into a directory like that.**

Mark Heath has a great blog post on a very similar topic:

> Why the `app_data` folder? Well that's a special ASP.NET folder that is intended for storing your application data. The web server will not serve up the contents of this folder, so everything in there is safe. It's also considered a special case for deployments - since it might contain application generated data files, its contents won't get deleted or reset when you deploy a new version of your app.

- Via Mark Heath - [https://markheath.net/post/managing-webjobs-with-kudu-api](https://markheath.net/post/managing-webjobs-with-kudu-api)
  
To expand on Marks last line, in Azure DevOps Pipelines -> Deployments -> Deploy AAS Task there is actually a checkbox to blow away the app_data folder if you want. I thought that was interesting.

The Kudu WebJob wiki also says:

> As an alternative, `d:\home\site\jobs\...` can be used instead of `d:\home\site\wwwroot\app_data\jobs\...`. This is useful when using Run-From-Zip, which makes `d:\home\site\wwwroot` become read-only.

But I haven't tested this.

### Third gotcha:

**Make sure to copy always the settings.job file. AND it uses [https://github.com/atifaziz/NCrontab](https://github.com/atifaziz/NCrontab) which requires a seconds field.** I first tried `5 0 * * *` and then had to go back and do `0 5 0 * * *` this means run 5 minutes after midnight every day.

This is trivial to verify, go to your AAS in the portal, and click the WebJob blade, you should see your schedule.

### Full YAML
```yaml
trigger:
- master

pool:
  vmImage: 'ubuntu-latest'

variables:
  buildConfiguration: 'Release'

steps:

- task: DotNetCoreCLI@2
  inputs:
    command: publish
    publishWebProjects: False
    arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
    zipAfterPublish: True

- task: PublishBuildArtifacts@1
  inputs:
    pathtoPublish: '$(Build.ArtifactStagingDirectory)' 
    artifactName: 'myWebsiteName'
```

Things id like to know more about:

- How to use Run-From-Zip WebJobs
- How to add a WebApp to my repo, and deploy that with my WebJob at the same time.

SEO Tags: Azure,App,Services,Deploying,.NET,Core,3.1,worker,schedule,triggered,WebJob,DevOps