4

I have an Azure Functions project that leverages Dependency Injection (Startup.cs injects services based on the different interfaces). Those services that implement the interfaces are using constructor dependency injection as well.

In one of those implementations, I want to call a method on a Durable Entity, but I prefer not to make the DurableEntityClient part of the method signature (as other implementations might not need the EntityClient at all). So therefore, I was hoping to see that IDurableEntityClient injected in the constructor of my class.

But it turns out the value is null. Wondering if this is something that is supported and feasible? (to have a DI-friendly way of injecting classes that want to get the EntityClient for the Functions runtime they are running in)

Some code snippets:

Startup.cs

builder.Services.AddSingleton<IReceiver, TableReceiver>();

Actual Function

public class ItemWatchHttpTrigger
{
    private IReceiver _receiver;

    public ItemWatchHttpTrigger(IReceiver receiver)
    {
        _receiver = receiver;
    }

    [FunctionName("item-watcher")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", Route = "item/{itemId}")]
        HttpRequest request, string itemId, [DurableClient] IDurableEntityClient client, ILogger logger)
    {
        // Actual implementation
    }
}

Referenced class

public class TableReceiver : IReceiver
{
    private IDurableEntityClient _entityClient;

    public TableReceiver(IDurableEntityClient client)
    {
        _entityClient = client; // client is null :(
    }
}
Sam Vanhoutte
  • 3,247
  • 27
  • 48
  • 1
    `IDurableEntityClient` is bind as as a binding parameter. I don't think you can use inject in constructor via DI. You can expose a method in `IReceiver` method to accept `IDurableEntityClient` which can be passed by the invoker of `IReceiver`. – user1672994 Dec 21 '20 at 12:26
  • I agree that would be a workaround, but it's not one I like, as I believe the `IDurableEntityClient` is something that is part of the implementation, and should not be part of the interface declaration. The best way would be something like `DurableEntityClient.GetFromContext()` in the SDK – Sam Vanhoutte Dec 21 '20 at 14:13
  • 1
    Not sure as I've not used it, but it seems that you can inject `IDurableClientFactory` via `services.AddDurableTask();` and retrieve/create a new `IDurableClient` client. `IDurableClient` inherits from `IDurableEntityClient `. See [here](https://github.com/Azure/azure-functions-durable-extension/blob/dev/src/WebJobs.Extensions.DurableTask/ContextInterfaces/IDurableClient.cs). Check if you can invoke the method exposed by `IDurableEntityClient` on retrieved object from factory. – user1672994 Dec 21 '20 at 15:06
  • Yes, I was just about to post this as answer, as I got this in reply to my github issue. Will write it out. tx – Sam Vanhoutte Dec 21 '20 at 15:08
  • https://github.com/Azure/azure-functions-durable-extension/issues/1616#issuecomment-748529560 – Sam Vanhoutte Dec 21 '20 at 15:08

1 Answers1

4

Based on the answer of my github issue, it seems it is possible to inject this in Startup, since the 2.4.0 version of the Microsoft.Azure.WebJobs.Extensions.DurableTask package:

Some code snippets:

Startup.cs

builder.Services.AddSingleton<IReceiver, TableReceiver>();
builder.Services.AddDurableClientFactory();

Referenced class

public class TableReceiver : IReceiver
{
    private IDurableEntityClient _entityClient;

    public TableReceiver(IDurableClientFactory entityClientFactory, IConfiguration configuration)
    {
        _entityClient = entityClientFactory.CreateClient(new DurableClientOptions
            {
                TaskHub = configuration["TaskHubName"]
            });
    }
}

Github issue

Sam Vanhoutte
  • 3,247
  • 27
  • 48