Rakesh Kumar
Rakesh Kumar

Reputation: 3129

DI in Azure Function using Simple Injector

I want to use Simple Injector to inject command handlers, ILogger and TelemetryClient in Azure Fuctions.

Here is my Azure Function:

[FunctionName("ReceiveEvent")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
    ILogger log,
    ICommandMapper commandMapper,
    ICommandValidator commandValidator,
    ICommandHandlerService commandHandlerService)
{
    log.LogInformation("ReceiveEvent HTTP trigger function started processing request.");

    IActionResult actionResult = null;

    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

    var command = await commandMapper.Map(requestBody);

    if (commandValidator.Validate(req, command, ref actionResult))
    {
        //TODO
        commandHandlerService.HandleCommand(command);
        return actionResult;
    }

    return actionResult;
}

Here is my Bootstrapper class:

public class Bootstrapper
{
    public static void Bootstrap(IEnumerable<Assembly> assemblies = null, bool verifyContainer = true)
    {
        Container container = new Container();

        container.Register(typeof(ICosmosDBRepository<>), typeof(CosmosDBRepository<>).Assembly);
        container.Register(typeof(IAzureBlobStorage), typeof(AzureBlobStorage).Assembly);
        container.Register(typeof(ICommandMapper), typeof(CommandMapper).Assembly);
        container.Register(typeof(ICommandValidator), typeof(CommandValidator).Assembly);
        container.Register(typeof(ICommandHandlerService), typeof(CommandHandlerService).Assembly);

        List<Assembly> myContextAssemlies = new List<Assembly>
            {
                 Assembly.GetAssembly(typeof(CardBlockCommandHandler)),
            };

        container.Register(typeof(ICommandHandler), myContextAssemlies, Lifestyle.Scoped);

        assemblies = assemblies == null
            ? myContextAssemlies
            : assemblies.Union(myContextAssemlies);

        if (verifyContainer)
        {
            container.Verify();
        }
    }
}

Now my question is, how I'll resolve the DI with this bootstrapper method in Azure Function?

Do I need to register bootstrap method in FunctionsStartup?

Upvotes: 1

Views: 644

Answers (1)

Steven
Steven

Reputation: 172646

With Simple Injector, you don't inject services into the Azure Function. This is not supported. Instead, the integration guide explains that:

Instead of injecting services into a Azure Function, move all the business logic out of the Azure Function, into an application component. The function's dependencies can become arguments of the component's constructor. This component can be resolved and called from within the Azure function.

For your particular case, this means executing the following steps:

1. move all the business logic out of the Azure Function, into an application component. The function's dependencies can become arguments of the component's constructor.

public sealed class ReceiveEventFunction
{
    private readonly ILogger log;
    private readonly ICommandMapper commandMapper;
    private readonly ICommandValidator commandValidator;
    private readonly ICommandHandlerService commandHandlerService;

    public ReceiveEventFunction(ILogger log, ICommandMapper commandMapper,
        ICommandValidator commandValidator, ICommandHandlerService commandHandlerService)
    {
        this.log = log;
        this.commandMapper = commandMapper;
        this.commandValidator = commandValidator;
        this.commandHandlerService = commandHandlerService;
    }
    
    public async Task<IActionResult> Run(HttpRequest req)
    {
        IActionResult actionResult = null;

        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

        var command = await commandMapper.Map(requestBody);

        if (commandValidator.Validate(req, command, ref actionResult))
        {
            commandHandlerService.HandleCommand(command);
            return actionResult;
        }

        return actionResult;    
    }
}

2 This component can be resolved and called from within the Azure function.

[FunctionName("ReceiveEvent")]
public static async Task<IActionResult> Run(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req)
{
    // Resolve the service
    var service = Bootstrapper.Container.GetInstance<ReceiveEventFunction>();
    
    // Invoke the service
    service.Run(req);
}

3. Final steps

To complete the configuration, you will have to ensure the (new) static Bootstrapper.Container field exists, and that ReceiveEventFunction is registered:

public class Bootstrapper
{
    public static readonly Container Container;

    static Bootstrapper()
    {
        Container = new Bootstrapper().Bootstrap();
    }

    public static void Bootstrap(
        IEnumerable<Assembly> assemblies = null, bool verifyContainer = true)
    {
        Container container = new Container();

        container.Register<ReceiveEventFunction>();

        ... // rest of your configuration here.
    }
}

Upvotes: 2

Related Questions