Friday, November 30, 2018

Scoped DI Provider for Azure Function

The azure function does not provide an in built support for dependency injection (at least at the time of writing this article). There is however an user voice ticket marked as started at this point.

Currently, there is a good nuget package available using which you could bring DI support with little effort as mentioned in its repo home page. The author of this package Boris Wilhelms, also wrote a blog post mentioning the working of this package if you would like to understand how it works.

Anyways, I was however looking for even simplified workaround until Microsoft provides native support.

So, here is the approach that I followed.

Created following wrapper class for DI:

public static class FunctionScopedDIProvider
{
    private static IServiceProvider serviceProvider;
    private static readonly object locker = new object();

    public static async Task Using(Func<IServiceProvider, Task> action)
    {
        if (serviceProvider == null)
        {
            lock (locker)
            {
                if (serviceProvider == null)
                {
                    serviceProvider = BuildServiceProvider();
                }
            }
        }

        var scopeFactory = serviceProvider.GetService<IServiceScopeFactory>();
        using (var scope = scopeFactory.CreateScope())
        {
            await action(scope.ServiceProvider);
        }
    }

    private static IServiceProvider BuildServiceProvider()
    {
        var services = new ServiceCollection();
        
        // TODO: Do your registrations here.
        // Ex: services.AddScoped<Imyservice, Myservice>();
        
        return services.BuildServiceProvider();
    }
}

Which can be used like this:

[FunctionName("Function1")]
public static async Task Run([QueueTrigger("myqueue-items", Connection = "")]string myQueueItem, ILogger log)
{
    await FunctionScopedDIProvider.Using(async provider =>
    {
        // The provider here would work as expeceted including scoped lifetime.
        // Ex: var myService = provider.GetService<IMyservice>();

        // TODO: You function logic goes here. 

        // A mock task completion as we don't have a real awaitable task here.
        await Task.CompletedTask;
    });

    log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
}

Note: The Using function of FunctionScopedDIProvider above not necessarily need to be async and so is the parameter. It can simply be an action delegate instead of function delegate.

This is how the non async version signature would look like.

public static void Using(Action<IServiceprovider> action)

Are you wondering why we need to do this, when we can easily get the DI provider by calling BuildServiceProvider method of ServiceCollectio? Well, its because singleton and scoped object liefetime support of the DI.

In other words, if you create new ServiceProvider each time, you won't get singleton behavior and if you reuse the ServiceProvider then you won't get scoped behavior (The reuse can be done by keeping it in a static variable).

So the solution that I come up with is by creating a static ServiceProvider  in a thread-safe manner and creating new scope each time with the help of in-built IServiceScopeFactory.

We can actually keep this stuff in the Run function's body itself but that's a cluttering code and not re-usable as well. So, created a nice wrapper with delegate using pattern (refer the second point in the article, titled - Measuring various function/method execution using StopWatch).

Enough talking, here is the full code. Enjoy your day!

Important: This code doesn't work if you would like to do the DI for function entry itself. For that you should use the solution provided by Boris Wilhelms which I mentioned in the beginning of this blog.

5 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. Great post!! It's good to share this kind of articles and I hope you'll share an article about Data Science. By giving an institute like 360DigiTMG.it is one of the best institutes for certified courses.
    data science course in noida

    ReplyDelete
  3. You should talk it's shocking. Your blog survey would extend your visitors. I was fulfilled to find this site.I expected to thank you for this phenomenal read!!

    HRDF training

    ReplyDelete
  4. On the off chance that your searching for Online Illinois tag sticker restorations, at that point you have to need to go to the privileged place.
    360DigiTMG

    ReplyDelete
  5. I have express a few of the articles on your website now, and I really like your style of blogging. I added it to my favorite’s blog site list and will be checking back soon…
    best institute for data science in hyderabad

    ReplyDelete