I recently needed to migrate some azure webjobs to .NET core 2.0. This is something that's not massively documented (probably because the .net libraries were only ported to core recently), so here's my write-up of how I set this all up.
My solution is an asp.net core 2.0 web app and a shared class library. I needed some console apps to that solution to run azure web jobs. The requirements of my webjobs are thusly:
- Trigger methods via scheduled timers (
- Trigger methods via queue items (
- Use the same DI mechanism as the web app
- Use the same config setup as the web app
Here's how I got all this working:
The webjob core bits
This was pretty simple, I created a .net core console app (if you're using VS, at the time of writing there are no templates for creating a webjob project, like there are for 'classic' .NET). Once I've done that I need 2 packages:
dotnet add package Microsoft.Azure.WebJobs dotnet add package Microsoft.Azure.WebJobs.Extensions
The first contains the azure webjobs SDK and allows us to wire things up. The second allows us to create timer triggers, so methods can run on a schedule - useful eh!
So now we're ready to configure DI, and um, configure configuration ;)
DI and Configuration
My web app uses the standard vanilla DI container that ships with asp.net core. I was mildly worried about getting this to work in a console app, but it was simple..
First of all, some packages:
dotnet add package Microsoft.Extensions.DependencyInjection dotnet add package Microsoft.Extensions.Configuration dotnet add package Microsoft.Extensions.Configuration.Json dotnet add package Microsoft.Extensions.Options.ConfigurationExtensions
That gives you everything you need for working with the DI container, and for setting up the configuration.
Then, you need to setup the DI container. In asp.net core you have a
ConfigureServices method in your
startup.cs where you do this. So, we can follow that pattern in our console app:
We create a serviceCollection, and pass it into
ConfigureServices, where we configure our services. In my example, I'm setting up
SomeUsefulClass as a dependency for our webjob, and then I'm setting up the class that contains the actual webjob methods -
WebJobsMethods (naming things is hard).
I also wanted to hook in my
appsettings.json configuration for my webjobs - you can see in my
ConfigureServices method I'm adding the
ConfigurationBuilder, telling it about my json file, and finally adding a configuration class called
MySettings to the DI container. Any class that "depends" on
MySettings will receive a fully populated class from my JSON now - perfect.
Also worth mentioning is the 2 lines that tell Azure what the storage account connection strings are - needed by the sdk for hooking up with your Queues, and for writing web jobs logs / stats.
The other thing you'll see in that code above is I need to configure the web job. Most of this is standard stuff, but notice I added a
JobActivator - I'm pointing it to a class called
CustomJobActivator - here it is:
So that simple resolver class just stores the DI container (service), and is then used by the web job to instantiate all classes needed, which it does simply by delegating to the DI container, hooray.
The web job methods
So now we need the actual web job methods - this bit is nice and easy now :)
See how the class that contains the web jobs methods can now just use DI - we have a CTOR that sets up the dependencies for that class. Then, in our methods, we can make full use of them. Awesome eh?