CI/CD for .NET framework web jobs

At the moment, there’s a weird in-between. If you want to run a background job that is continuous and/or requires vnet integration, you might have to use a web job. Even more so, if you’re having to run .NET Framework, your best best is to run a v1 web job, not v2, not v3. As the Azure team is pushing heavily adopting .NET Core, the Web Job SDK is moving along with it.

My weird issue

I wanted to move a .NET Framework 4.7 Windows Service to Azure using a Web Job. It had to trigger several little functions on a timer, fairly frequently (as often as every 5 seconds for some). This background job also had interact with IaaS services and therefore connect to a vnet.

So, I solved it by creating a .NET Framework Web Job using File -> New Project -> Web Job. This is assuming you have the Azure Developer Pack installed to Visual Studio. From here, I created a continuous web job and installed the web job extensions that I could use a TimerTrigger.

The pipeline

The hard part was creating the CI/CD pipeline. Turns out that the new, short, sweet .csproj don’t play nice with the older v1 web job tooling.

Going back in time

There’s this old blog post that has a lot of good information on how the older web jobs were configured before. I didn’t have to follow a lot of it, because well, I was using Azure DevOps with the built-in tasks to deploy the web job.

The main takeaways:

  • For continuous web jobs, enable ‘Always On’ the app service
  • Ensure you the Microsoft.Web.WebJobs.Publish NuGet package installed on your web job project
  • Ensure you’re publishing with the right MsBuild properties (see pipeline section below)
  • There’s an open issue that shed’s some light if you want to make a web job work with the new .csproj as seen by .NET Framework 4.7 and above. If you don't do this, your web deploy package will be empty.
  • You’re going to need a webjob-publish-settings.json file under the Properties folder of the project.

    <PropertyGroup>
        <IsWebJobProject>true</IsWebJobProject>
        <WebJobName>$(AssemblyName)</WebJobName>
        <WebJobType>Continuous</WebJobType>
    </PropertyGroup>
    

The tasks

First, build the solution with the following MSBuild arguments. They should be the same you would use to create a Web Deploy package for traditional Windows-based App Service deployments

- task: VSBuild@1
  displayName: 'Build Solution'
  inputs:
    solution: '**\*.sln'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)/"'
    platform: 'Any CPU'
    configuration: 'Debug'

Then, when you’re wanting to deploy, use the older AzureRmWebAppDeployment@4 task. (Assuming, you published the zip as a build artifact).

- task: AzureRmWebAppDeployment@4
  displayName: 'Deploy Web Job'
  inputs:
    azureSubscription: 'my-subscription-service-connection'
    WebAppName: 'azapp-myapp-dev-001'
    package: '$(Pipeline.Workspace)/**/MyWebJob.zip'

That’s it! I didn’t really cover how to create the web job on Azure.