Dependency injection using Azure WebJobs SDK? Dependency injection using Azure WebJobs SDK? azure azure

Dependency injection using Azure WebJobs SDK?


Azure WebJobs SDK now supports instance methods. Combining this with a custom IJobActivator allows you to use DI.

First, create the custom IJobActivator that can resolve a job type using your favourite DI container:

public class MyActivator : IJobActivator{    private readonly IUnityContainer _container;    public MyActivator(IUnityContainer container)    {        _container = container;    }    public T CreateInstance<T>()    {        return _container.Resolve<T>();    }}

You need to register this class using a custom JobHostConfiguration:

var config = new JobHostConfiguration{    JobActivator = new MyActivator(myContainer)};var host = new JobHost(config);

Then, you can use a simple class with instance methods for your jobs (here I'm using Unity's constructor injection feature):

public class MyFunctions{    private readonly ISomeDependency _dependency;    public MyFunctions(ISomeDependency dependency)    {        _dependency = dependency;    }    public Task DoStuffAsync([QueueTrigger("queue")] string message)    {        Console.WriteLine("Injected dependency: {0}", _dependency);        return Task.FromResult(true);    }}


This is how I handled scoping using the new SDK. Using the IJobactivator as described by Alexander Molenkamp.

public class ScopedMessagingProvider : MessagingProvider{    private readonly ServiceBusConfiguration _config;    private readonly Container _container;    public ScopedMessagingProvider(ServiceBusConfiguration config, Container container)        : base(config)    {        _config = config;        _container = container;    }    public override MessageProcessor CreateMessageProcessor(string entityPath)    {        return new CustomMessageProcessor(_config.MessageOptions, _container);    }    private class CustomMessageProcessor : MessageProcessor    {        private readonly Container _container;        public CustomMessageProcessor(OnMessageOptions messageOptions, Container container)            : base(messageOptions)        {            _container = container;        }        public override Task<bool> BeginProcessingMessageAsync(BrokeredMessage message, CancellationToken cancellationToken)        {            _container.BeginExecutionContextScope();            return base.BeginProcessingMessageAsync(message, cancellationToken);        }        public override Task CompleteProcessingMessageAsync(BrokeredMessage message, FunctionResult result, CancellationToken cancellationToken)        {            var scope = _container.GetCurrentExecutionContextScope();            if (scope != null)            {                scope.Dispose();            }            return base.CompleteProcessingMessageAsync(message, result, cancellationToken);        }    }}

You can the use your custom MessagingProvider in your JobHostConfiguration like

var serviceBusConfig = new ServiceBusConfiguration{     ConnectionString = config.ServiceBusConnectionString};serviceBusConfig.MessagingProvider = new ScopedMessagingProvider(serviceBusConfig, container);jobHostConfig.UseServiceBus(serviceBusConfig);


After asking my own question about how to handle scoping ... I've just came up to this solution: I don't think this is ideal but I couldn't find any other solution for the moment.

In my example I am dealing with ServiceBusTrigger.

As I am using SimpleInjector, the implementation of the IJobActivator interface looks like that:

public class SimpleInjectorJobActivator : IJobActivator{    private readonly Container _container;    public SimpleInjectorJobActivator(Container container)    {        _container = container;    }    public T CreateInstance<T>()    {        return (T)_container.GetInstance(typeof(T));    }}

Here, I am dealing with Triggered webjobs.

So I have two dependencies:

  • A singleton:

    public interface ISingletonDependency { }public class SingletonDependency : ISingletonDependency { }
  • And another that need to live only the time my function is triggered:

    public class ScopedDependency : IScopedDependency, IDisposable{    public void Dispose()    {         //Dispose what need to be disposed...    }}

So in order to have a process that run independently from the webjob. I've encapsulated my process into a class :

public interface IBrokeredMessageProcessor{    Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token);}public class BrokeredMessageProcessor : IBrokeredMessageProcessor{    private readonly ISingletonDependency _singletonDependency;    private readonly IScopedDependency _scopedDependency;    public BrokeredMessageProcessor(ISingletonDependency singletonDependency, IScopedDependency scopedDependency)    {        _singletonDependency = singletonDependency;        _scopedDependency = scopedDependency;    }    public async Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token)    {        ...    }}

So now when the webjob starts, I need to register my dependencies depending their scopes:

class Program{    private static void Main()    {        var container = new Container();        container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();        container.RegisterSingleton<ISingletonDependency, SingletonDependency>();        container.Register<IScopedDependency, ScopedDependency>(Lifestyle.Scoped);        container.Register<IBrokeredMessageProcessor, BrokeredMessageProcessor>(Lifestyle.Scoped);        container.Verify();        var config = new JobHostConfiguration        {            JobActivator = new SimpleInjectorJobActivator(container)        };        var servicebusConfig = new ServiceBusConfiguration        {            ConnectionString = CloudConfigurationManager.GetSetting("MyServiceBusConnectionString")        };        config.UseServiceBus(servicebusConfig);        var host = new JobHost(config);        host.RunAndBlock();    }}

And this is the triggered job:

  • Only have one dependency : the IoC container. Because this class is part of my composition root, it should be ok.
  • It handle the scope into the triggered function.

    public class TriggeredJob{    private readonly Container _container;    public TriggeredJob(Container container)    {        _container = container;    }    public async Task TriggeredFunction([ServiceBusTrigger("queueName")] BrokeredMessage message, CancellationToken token)    {        using (var scope = _container.BeginExecutionContextScope())        {            var processor = _container.GetInstance<IBrokeredMessageProcessor>();            await processor.ProcessAsync(message, token);        }    }}