If you are a user of Azure App Service you are probably aware of the Azure WebJobs. If it's not case the case, I advise you to take a look at it because Azure WebJobs are very powerful to run background processes and comes at no extra cost when already using Azure App Service (Web Apps, Mobile Apps, API Apps, Logic Apps).
Also Azure WebJobs come along the Azure WebJobs SDK that has a great trigger system to work with Azure Storage. For example a job function can be automatically started when a message is inserted into an Azure Queue storage.
Behind the scene the trigger system will create a new instance of the class containing the function, then the function will be invoked. The responsibility of creating instances of job classes is given to the JobActivator.
DefaultJobActivator
Now let's take a look at the original source code of the DefaultJobActivator on GitHub:
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System; namespace Microsoft.Azure.WebJobs.Host.Executors { internal class DefaultJobActivator : IJobActivator { private static readonly DefaultJobActivator Singleton = new DefaultJobActivator(); private DefaultJobActivator() { } public static DefaultJobActivator Instance { get { return Singleton; } } public T CreateInstance<T>() { return Activator.CreateInstance<T>(); } } }
Here you can notice two things:
The problem with this implementation is that only an instance of a job class with parameterless constructor can be created.
Fortunately for us the Azure WebJobs SDK allows to specify a custom JobActivator in the JobHostConfiguration.
In the original source code on GitHub we can see that the DefaultJobActivator is used when creating a new JobHostConfiguration:
AddService<IJobActivator>(DefaultJobActivator.Instance);
Now let's take a look at how to replace the default job activator with our own using Unity!
Creation
For our needs we will create the following interface inheriting from IJobActivator:
using System; using Microsoft.Azure.WebJobs.Host; namespace AzureWebJobs.JobActivatorUnity.Dependencies { public interface IJobActivatorDependencyScope : IJobActivator, IDisposable { } }
Now we will create the Unity implementation of it:
using System; using AzureWebJobs.JobActivatorUnity.Dependencies; using Microsoft.Practices.Unity; namespace AzureWebJobs.JobActivatorUnity.Unity { public class UnityJobActivatorDependencyScope : IJobActivatorDependencyScope { private readonly IUnityContainer container; public UnityJobActivatorDependencyScope(IUnityContainer container) { if (container == null) throw new ArgumentNullException("container"); this.container = container; } public T CreateInstance<T>() { return this.container.Resolve<T>(); } public void Dispose() { this.container.Dispose(); } } }
Thanks to this implementation the responsibility of creating instances is given to the Unity container through the invocation of container.Resolve<T>().
Example of use
We have created a custom JobActivator, now we will learn how to use it in a simple scenario.
First we will configure the Unity container and register a simple service to it:
using System; using AzureWebJobs.JobActivatorUnity.Contracts; using AzureWebJobs.JobActivatorUnity.Services; using Microsoft.Practices.Unity; namespace AzureWebJobs.JobActivatorUnity { public class UnityConfig { #region Unity Container private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() => { var container = new UnityContainer(); RegisterTypes(container); return container; }); /// <summary> /// Gets the configured Unity container. /// </summary> public static IUnityContainer GetConfiguredContainer() { return container.Value; } #endregion /// <summary>Registers the type mappings with the Unity container.</summary> /// <param name="container">The unity container to configure.</param> public static void RegisterTypes(IUnityContainer container) { container.RegisterType<INumberService, NumberService>(new ContainerControlledLifetimeManager()); } } }
Here nothing special as it's a common Unity container configuration. The INumberService is used for the example and will allow us to return a random number.
Now we will configure our WebJob to use our custom IJobActivator:
using AzureWebJobs.JobActivatorUnity.Unity; using Microsoft.Azure.WebJobs; namespace AzureWebJobs.JobActivatorUnity { // To learn more about Microsoft Azure WebJobs SDK, please see http://go.microsoft.com/fwlink/?LinkID=320976 class Program { // Please set the following connection strings in app.config for this WebJob to run: // AzureWebJobsDashboard and AzureWebJobsStorage static void Main() { var config = new JobHostConfiguration() { JobActivator = new UnityJobActivatorDependencyScope(UnityConfig.GetConfiguredContainer()) }; var host = new JobHost(config); // The following code ensures that the WebJob will be running continuously host.RunAndBlock(); } } }
In our job function we use can now use the INumberService:
using System; using System.IO; using AzureWebJobs.JobActivatorUnity.Contracts; using Microsoft.Azure.WebJobs; namespace AzureWebJobs.JobActivatorUnity { public class Functions { private readonly INumberService numberService; public Functions(INumberService numberService) { if (numberService == null) throw new ArgumentNullException("numberService"); this.numberService = numberService; } // This function will get triggered/executed when a new message is written // on an Azure Queue called queue. public void ProcessQueueMessage([QueueTrigger("queue")] string message, TextWriter log) { log.WriteLine("New random number {0} for message: {1}", this.numberService.GetRandomNumber(), message); } } }
We can pay attention to several things here:
To go further
When a function is triggered by the Azure WebJobs trigger system it is interesting to understand that a new instance of the class containing the function is created via the IJobActivator before invoking the function itself. This is important because every time a function is triggered it gives you latitude on the configuration of the dependencies' lifetime.
Summary
We have seen how to use Unity as job activator and implement IoC and DI in a Microsoft Azure WebJob simple scenario.
Of course instead of using Unity you are free to use another IoC container like Autofac, Ninject, Simple Injector, etc.
Now in the scenario we just went through you may have asked yourself: "But how can I get a dependency scope only for the lifetime of my function?".
Yes what if I want to get dependencies that will be just instantiated for my function and make sure that those resources will be disposed when the function's job is done. Like reaching a database for the purpose of the function and close the connection, dispose all the resources properly. Well that will be the subject of my next article about Azure WebJobs in a more complex scenario, stay tuned!
You can download the example solution here:
Or
Browse the GitHub repository
(Note that the project uses Microsoft.Azure.WebJobs version 1.1.2)
Please feel free to comment or contact me if you have any question about this article.