66

The problem is that the Azure WebJobs SDK supports only public static methods as job entry-points which means there is no way of implementing constructor/property injection.

I am unable to find anything about this topic in official WebJobs SDK documentation/resources. The only solution that I came across is based on service locator (anti) pattern described on this post here.

Is there a good way to use "proper" dependency injection for projects based on Azure WebJobs SDK?

Milos Mrdovic
  • 1,441
  • 1
  • 17
  • 30
  • Can you elaborate a little? Are you trying to get a "per-job" scope to objects coming out of your container, similar to a per-request on a standard web app? – Veatch May 19 '15 at 14:55
  • Yes. I have edited the question. Please see the blog post I linked for more details. – Milos Mrdovic May 19 '15 at 15:07
  • Assumming that you're running a console application, you should use DI as you would in any console application. That being said, the only method I found is using something similar than the anti-pattern in the blog post. I can provide an example using Ninject upon request. – lopezbertoni May 19 '15 at 18:51

5 Answers5

92

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);
    }
}
Sander Molenkamp
  • 1,101
  • 7
  • 5
  • Great! This eliminates the need to manually resolve all dependencies from within job functions. Too bad you didn't show up earlier - now I have to rewrite a whole bunch of stuff. – Milos Mrdovic May 26 '15 at 13:39
  • 2
    I want to point out that this is only support from v 1.0.1 and upwards of the library. – VeldMuijz Jul 23 '15 at 12:26
  • 3
    For a triggered job (not using queues, etc.), do we need to manually trigger the function to use the job activator? `CallMethod(...)`? – kamranicus Aug 07 '15 at 14:32
  • Where do you put the custom `JobHostConfiguration` and what do you do with the `host` ? – Marcus Jun 06 '16 at 09:35
  • A big win for testability (through stubs, mocks etc). – sammy34 Jun 06 '16 at 18:22
  • 2
    what exactly is the myContainer passed into the MyActivator constructor? – Chaliswaan Choor Sep 21 '16 at 18:58
  • I have the same question as @ChaliswaanChoor what is myContainer? – Høgsdal Mar 09 '17 at 09:43
  • 2
    In this example, myContainer is an instance of IUnityContainer, which is a Dependency Injection framework. You don’t need to use Unity however, the same pattern applies to other Dependency Injection frameworks such as Ninject or Autofac. – Sander Molenkamp Mar 10 '17 at 10:07
  • I'm missing something here. I know that the Unity container is passed to the JobActivator, which in turn is part of the config, which is again part of the web job host, and (I'm guessing) that's how the functions can know about the interface-to-class information held in the Unity container. What I don't understand is where the construction injection happens - doesn't there need to be a call like `var _dependency = container.Resolve();` somewhere? – Tola Odejayi Feb 21 '19 at 19:40
  • The constructor argument does not need to be resolved manually. The `MyFunctions` class is being instantiated by the registered JobActivator, in this case the `MyActivator` class. So the `MyActivator` class will make a `_container.Resolve` call. Now it's up to Unity to resolve the `ISomeDependency` argument of the `MyFunctions` constructor. Unity can do this by itself as long as the container contains a registration for `ISomeDependency`. – Sander Molenkamp Feb 26 '19 at 09:33
12

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);
bmeredith
  • 655
  • 6
  • 8
Niklas Arbin
  • 652
  • 6
  • 14
  • Just to clarify, this will give us a per-job-scope? But it is specific to jobs based on Azure Service Bus queue triggers? – Søren Boisen Jan 17 '16 at 13:14
  • This will setup a per message scope. This example is for ServiceBus triggers, but I think the MessageProcessor is open to extension for other triggers as well. – Niklas Arbin Jan 18 '16 at 17:07
  • What is `BeginExecutionContextScope()`? Is this method specific to some DI container implementation? What would be the equivalent for Unity? – UserControl Sep 18 '17 at 12:14
12

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);
            }
        }
    }
    
Community
  • 1
  • 1
Thomas
  • 24,234
  • 6
  • 81
  • 125
  • Do you have a typo in your SimpleInjectorBootstrapper method? It seems to configure SingletonDependency and ScopedDependency in exactly the same way. – Søren Boisen Jan 17 '16 at 13:10
  • @SørenBoisen, I've edited my answer, you were right. The scoped dependency must be registered as a instance per call. – Thomas Jan 17 '16 at 19:49
  • Where do you start the scope? I expect to see a call to `container.BeginExecutionContextScope()` as part of your answer. Without an active scope, resolving `BrokeredMessageProcessor` will fail, because it depends on a scoped dependency. Where do you start the scope? – Steven Feb 03 '16 at 08:54
  • Ow sugar! You're the same guy as asking the last Simple Injector question :(. – Steven Feb 03 '16 at 08:57
  • Yeah @Steven I tried to find a way to implement correctly DI with Azure Webjobs... But in this example my dependencies are not disposable, so is it a real problem not to have an active scope ? I definitively need to ask a question to the Azure Webjob team ^^ – Thomas Feb 03 '16 at 09:01
  • @Steven, I've updated my answer according to the solution I've decided to implement. – Thomas Feb 05 '16 at 03:58
  • 2
    Even when instances are not disposable, you might want to share instances throughout the request (e.g. a DbContext). – Steven Feb 05 '16 at 07:51
  • I really wish there was a way to not have to resolve the dependencies within each trigger :'( – CamHart Apr 16 '18 at 20:20
  • Have a look at this question, depends on which trigger you need, it may help https://stackoverflow.com/questions/35186456/azure-triggered-webjobs-scope-for-dependency-injection – Thomas Apr 17 '18 at 07:58
  • Doesn't this answer have a bug? Shouldn't the GetInstance call be on scope and not _container? – Agendum Jun 01 '19 at 05:00
  • Thi answer was post a while ago so the implementation may have changed. – Thomas Jun 01 '19 at 07:49
5

All answers to the question are outdated now. Using the latest packages you can easily get constructor injection right out of the box. Two steps are only required:

  1. Create the event handler function as an instance method in a non-static class. Let's call the class QueueFunctions.

  2. Add your class to the list of services.

     builder.ConfigureServices(services =>
     {
         // Add 
         // dependencies
         // here
    
         services.AddScoped<QueueFunctions>();
     });
    

Now, you'll be able to inject dependencies through the constructor.

Ehsan Mirsaeedi
  • 6,924
  • 1
  • 41
  • 46
4

I've used a couple patterns that rely on the concept of child containers/scopes (depending on the terminology of your IoC container of choice). Not sure which ones support it, but I can tell you that StructureMap 2.6.x and AutoFac do.

The idea is to spin up a child scope for each message coming in, inject any context that's unique to that request, resolve the top-level object from the child scope, and then run your process.

Here's some generalized code showing it with AutoFac. It does do a direct resolve from the container, similar to the anti-pattern you're attempting to avoid, but it's been isolated to one place.

In this case, it's using a ServiceBusTrigger to fire the job, but could be anything - a job host could potentially have a list of these for the different queues/processes.

public static void ServiceBusRequestHandler([ServiceBusTrigger("queuename")] ServiceBusRequest request)
{
   ProcessMessage(request);
}

This method is called by all instances of the above methods. It wraps creation of the child scope in a using block to make sure things are cleaned up. Then, any objects that would vary per request and contain context used by other dependencies (user/client information, etc) would be created and injected into the child container (in this example, the IRequestContext). Finally, the component doing the work would be resolved from the child container.

private static void ProcessMessage<T>(T request) where T : IServiceBusRequest
{
    try
    {
        using (var childScope = _container.BeginLifetimeScope())
        {
            // create and inject things that hold the "context" of the message - user ids, etc

            var builder = new ContainerBuilder();
            builder.Register(c => new ServiceRequestContext(request.UserId)).As<IRequestContext>().InstancePerLifetimeScope();
            builder.Update(childScope.ComponentRegistry);

            // resolve the component doing the work from the child container explicitly, so all of its dependencies follow

            var thing = childScope.Resolve<ThingThatDoesStuff>();
            thing.Do(request);
        }
    }
    catch (Exception ex)
    {

    }
}
Veatch
  • 893
  • 7
  • 11
  • Thanks! This is a solid approach based on which I have implemented my initial dependency injection infrastructure. However, now that we have an updated SDK, I am just using the built-in method which works flawlessly. – Milos Mrdovic May 26 '15 at 13:46
  • @veatch you don't need to create a new container builder and update the scope, _container.BeginLifetimeScope() allows you to register new dependencies now. – Wiebe Tijsma Oct 26 '17 at 11:53