Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Registering BlobContainerClient and Injecting into Isolated Function

I am using net8 Azure Functions with Isolated model.

In the docs the sample shows using AddBlobServiceClient() to register an IAzureClientFactory<BlobServiceClient> which can then be injected into the function.

I would like to register two BlobContainerClient's each with its own container. My attempt is:

services.AddSingleton<BlobContainerClient>(provider =>
{
    var configuration = provider.GetRequiredService<IConfiguration>();
    var storageContainerName = configuration.GetValue<string>("AzureWebJobsStorage");
    var blobServiceClient = provider.GetRequiredService<IAzureClientFactory<BlobServiceClient>>()
        .CreateClient("inbound");
    var blobContainerClient = blobServiceClient.GetBlobContainerClient(storageContainerName);
    return blobContainerClient;
});

The problem with this is I now have a hard dependency upon BlobContainerClient which is difficult to test.

One extension method on AddBlobServiceClient is WithName() but I fail to see what use this is as I cannot see how to configure a BlobContainerClient as part of the registration of the BlobServiceClient.

In summary, my question is: How can I configure two individual BlobContainerClient's using the AddBlobServiceClient method in Program.cs and then inject one of two possibilities into a function?

like image 831
phil Avatar asked Oct 17 '25 11:10

phil


1 Answers

It took quite some digging but here's how I achieved what I wanted and it remains testable which is awesome. It means I can configure my container names during registration and just inject them using an appropriate name.

Program.cs

...
builder.AddBlobServiceClient(Environment.GetEnvironmentVariable("AzureWebJobsStorage"))
    .WithName("in1");
builder.AddClient<BlobContainerClient, BlobClientOptions>((options, provider) =>
{
    var configuration = provider.GetRequiredService<IConfiguration>();
    var storageContainerName = configuration.GetValue<string>("AzureWebJobsStorage");
    var blobServiceClient = provider.GetRequiredService<IAzureClientFactory<BlobServiceClient>>()
        .CreateClient("in1");
    var blobContainerClient = blobServiceClient.GetBlobContainerClient("inbound");
    return blobContainerClient;
})
.WithName("in2");
builder.AddClient<BlobClient, BlobClientOptions>((opts, provider) =>
{
    var blobContainerClient = provider.GetRequiredService<IAzureClientFactory<BlobContainerClient>>().CreateClient("in2");
    var blobClient = blobContainerClient.GetBlobClient("hello");
    return blobClient;
})
.WithName("in3");

builder.AddClient<BlobContainerClient, BlobClientOptions>((options, provider) =>
    {
        var configuration = provider.GetRequiredService<IConfiguration>();
        var storageContainerName = configuration.GetValue<string>("AzureWebJobsStorage");
        var blobServiceClient = provider.GetRequiredService<IAzureClientFactory<BlobServiceClient>>()
            .CreateClient("in1");
        var blobContainerClient = blobServiceClient.GetBlobContainerClient("outbound");
        return blobContainerClient;
    })
    .WithName("out1");
builder.AddClient<BlobClient, BlobClientOptions>((opts, provider) =>
    {
        var blobContainerClient = provider.GetRequiredService<IAzureClientFactory<BlobContainerClient>>().CreateClient("out1");
        var blobClient = blobContainerClient.GetBlobClient("goodbye");
        return blobClient;
    })
    .WithName("out2");
...

And then in your consuming class:

public Consumer(ILogger<NewClientHandoff> logger,
    IAzureClientFactory<BlobServiceClient> blobClientFactory,
    IAzureClientFactory<BlobContainerClient> c,
    IAzureClientFactory<BlobClient> d)
{
    _c = c.CreateClient("in1");
    _d = d.CreateClient("out2");
...
like image 135
phil Avatar answered Oct 20 '25 00:10

phil