RobVious
RobVious

Reputation: 12915

Using Unity to inject dependency from another project with Azure WebJob

I have two projects in my solution - a web project, and a console app.

Web Project

From within my web project, I have the following working:

public class TestService : BaseService {
    private BrowseService _browseService;
    public TestService(BrowseService browseService) {
        _browseService = browseService;
    }

    public ApiResponseDto DoStuff(string username) {

        using (var db = new AppContext()) {
            var user = db.FindUser(username);
            // do stuff with _browseService here
        }
    }
 }

I'm using Unity for DI here.

Console App

Now, I reference my web project from my console app and do the following:

public class Functions {
    private TestService _testService;
    public Functions(TestService testService) {
        _testService = testService;
    }

    public static void ProcessStuff([QueueTrigger("my-queue")] string userId) {
        using (var db = new AppContext()) { // works
            _testService.DoStuff(userId) // _testService isn't available
        }
    }

Problem

How do I get DI working in my console app? I've added Unity and then I do this:

    static void Main() {
        var container = new UnityContainer();
        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        var host = new JobHost();
        // The following code ensures that the WebJob will be running continuously
        host.RunAndBlock();
    }

However, the constructor above never gets hit and _testService is never available.

Update

I've attempted the following:

static void Main() {
    var container = new UnityContainer();
    var host = container.Resolve<JobHost>().
    host.RunAndBlock();
}

However I get an exception:

Microsoft.Practices.Unity.ResolutionFailedException was unhandled
_HResult=-2146233088 _message=Resolution of the dependency failed, type = "Microsoft.Azure.WebJobs.JobHost", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value. ----------------------------------------------- At the time of the exception, the container was:

Resolving Microsoft.Azure.WebJobs.JobHost,(none) Resolving parameter "configuration" of constructor Microsoft.Azure.WebJobs.JobHost(Microsoft.Azure.WebJobs.JobHostConfiguration configuration) Resolving Microsoft.Azure.WebJobs.JobHostConfiguration,(none) Resolving parameter "dashboardAndStorageConnectionString" of constructor Microsoft.Azure.WebJobs.JobHostConfiguration(System.String dashboardAndStorageConnectionString) Resolving System.String,(none)

HResult=-2146233088 IsTransient=false Message=Resolution of the dependency failed, type = "Microsoft.Azure.WebJobs.JobHost", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - The type String cannot be constructed. You must configure the container to supply this value.

Update 2

I now have the following per this question Dependency injection using Azure WebJobs SDK?:

class Program {
    static void Main() {
        var container = new UnityContainer();
        var config = new JobHostConfiguration {
            JobActivator = new MyActivator(container)
        };
        var host = new JobHost(config);
        // The following code ensures that the WebJob will be running continuously
        host.RunAndBlock();
    }
}

public class MyActivator : IJobActivator {
    private readonly IUnityContainer _container;

    public MyActivator(IUnityContainer container) {
        _container = container;
    }

    public T CreateInstance<T>() {
        return _container.Resolve<T>();
    }
}

However, _testService is still null and the injection constructor for Functions is never executed.

Upvotes: 0

Views: 1064

Answers (2)

Jambor - MSFT
Jambor - MSFT

Reputation: 3293

Based on your code, I have tested it on my side and worked it out. Please try to follow the code below to check whether it could help you:

Web Project

public class TestService : BaseService
{
    private BrowseService _browseService;
    public TestService(BrowseService browseService)
    {
        _browseService = browseService;
    }

    public string DoStuff(string username)
    {
        return _browseService.DoStuff(username);
    }
}

public class BaseService { }

public abstract class BrowseService
{
    public abstract string DoStuff(string username);
}

public class MyBrowseService : BrowseService
{
    public override string DoStuff(string username)
    {
        return string.Format("MyBrowseService.DoStuff is invoked with value={0}", username);
    }
}

Console App

1)Functions.cs

public class Functions
{
    private static TestService _testService;
    public Functions(TestService testService)
    {
        _testService = testService;
    }

    public void ProcessStuff([QueueTrigger("my-queue")] string userId)
    {
        try
        {
            Console.WriteLine("ProcessStuff is invoked with value={0}", userId);
            string result = _testService.DoStuff(userId);
            Console.WriteLine("ProcessStuff return the result:\r\n{0}", result);
        }
        catch (Exception e)
        {
            Console.WriteLine("ProcessStuff executed with errors.\r\n{0}\r\n{1}", e.Message, e.StackTrace);
        }
    }
}

Note: You should set the WebJob function as an instance function not a static function.

2)Program.cs

static void Main()
{
    UnityContainer container = new UnityContainer();
    container.RegisterType<BrowseService, MyBrowseService>();
    container.RegisterType<Functions>(); //Need to register WebJob class
    var config = new JobHostConfiguration()
    {
        JobActivator = new UnityJobActivator(container)
    };
    var host = new JobHost(config);
    host.RunAndBlock();
}

Result: enter image description here

Upvotes: 1

Jeff S
Jeff S

Reputation: 7484

DependencyResolver is an MVC construct; it isn't used in a console app. To make this work, change your main method to:

static void Main() {
        var container = new UnityContainer();
        var host = container.Resolve<JobHost>().
        host.RunAndBlock();
    }

Then, as long as you use constructor injection, everything should work as expected.

Upvotes: 0

Related Questions