aspire icon indicating copy to clipboard operation
aspire copied to clipboard

AzureStorage auto create blob containers

Open RussKie opened this issue 8 months ago • 4 comments

Resolves #5167

Description

Checklist

  • Is this feature complete?
    • [x] Yes. Ready to ship.
    • [ ] No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • [x] Yes
    • [ ] No
  • Did you add public API?
    • [x] Yes
      • If yes, did you have an API Review for it?
        • [ ] Yes
        • [x] No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • [ ] Yes
        • [ ] No
    • [ ] No
  • Does the change make any security assumptions or guarantees?
    • [ ] Yes
      • If yes, have you done a threat model and had a security review?
        • [ ] Yes
        • [ ] No
    • [x] No
  • Does the change require an update in our Aspire docs?

RussKie avatar Apr 29 '25 01:04 RussKie

Are you doing the client integration side of this as well?

davidfowl avatar Apr 29 '25 01:04 davidfowl

For the most part this changeset copies the patterns implemented for AzureServiceBus.

I tested it locally in the emulator and deploying to Azure (configuring the Azure subscription details in secrets.json)

Emulator

image

Azure

var builder = DistributedApplication.CreateBuilder(args);

var storage = builder.AddAzureStorage("storage");
var blobs = storage.AddBlobs("blobs");
var blobContainer = blobs.AddBlobContainer("mycontainer");

var queues = storage.AddQueues("queues");

builder.AddProject<Projects.AzureStorageEndToEnd_ApiService>("api")
       .WithExternalHttpEndpoints()
       .WithReference(blobs).WaitFor(blobs)
       .WithReference(blobContainer).WaitFor(blobContainer)
       .WithReference(queues).WaitFor(queues);

image

RussKie avatar Apr 29 '25 02:04 RussKie

Are you doing the client integration side of this as well?

Yes, though I may do it as a follow up.

RussKie avatar Apr 29 '25 02:04 RussKie

The latest iteration adds the ability to register BlobContainerClient with AddAzureBlobContainerClient(), and then get the client directly:

builder.AddAzureBlobContainerClient("foocontainer");

var app = builder.Build();
app.MapGet("/", async (BlobContainerClient bcc) =>
{
}

image

RussKie avatar Apr 30 '25 07:04 RussKie

@davidfowl @eerhardt @captainsafia @mitchdenny: I believe the client integration is complete, reviews are appreciated. There are also few open questions for which I'd appreciate your input.

I tested various scenarios, e.g.:

// Host

var storage = builder.AddAzureStorage("storage");
var blobs = storage.AddBlobs("blobs");
blobs.AddBlobContainer("mycontainer1", blobContainerName: "test-container-1");
blobs.AddBlobContainer("mycontainer2", blobContainerName: "test-container-2");

var storage2 = builder.AddAzureStorage("storage2");
var blobs2 = storage2.AddBlobs("blobs2");
var blobContainer2 = blobs2.AddBlobContainer("foocontainer", blobContainerName: "foo-container");

builder.AddProject<Projects.AzureStorageEndToEnd_ApiService>("api")
       .WithExternalHttpEndpoints()
       .WithReference(blobs).WaitFor(blobs)
       .WithReference(blobContainer2).WaitFor(blobContainer2)
       .WithReference(queues).WaitFor(queues);

// Client

builder.AddAzureBlobClient("blobs");
builder.AddAzureBlobContainerClient("foocontainer");

app.MapGet("/test", async (BlobServiceClient bsc, BlobContainerClient fooContainerClinet) => { }
builder.AddAzureBlobClient("blobs");
builder.AddKeyedAzureBlobContainerClient("foocontainer");

app.MapGet("/test", async (BlobServiceClient bsc, [FromKeyedServices("foocontainer")] BlobContainerClient fooContainerClinet) => { }
builder.AddAzureBlobClient("blobs")
       .AddKeyedAzureBlobContainerClient(blobContainerName: "test-container-1")
       .AddKeyedAzureBlobContainerClient(blobContainerName: "test-container-2");

app.MapGet("/", async (BlobServiceClient bsc, 
                       [FromKeyedServices("test-container-1")] BlobContainerClient keyedContainerClient1,
                       [FromKeyedServices("test-container-2")] BlobContainerClient keyedContainerClient2) => { }

AF are TBD, as well as various tests.

RussKie avatar May 01 '25 06:05 RussKie

@eerhardt @sebastienros I added tests but I'm really unsure if or what more tests are needed.

Implementation-wise, I think, this is ready.

RussKie avatar May 06 '25 03:05 RussKie

@eerhardt please let me know if there are any tweaks you want to make it and I'll action those as a follow up.

RussKie avatar May 07 '25 00:05 RussKie

https://github.com/dotnet/aspire/blob/c029d9caa81ca6bbae49f47925c12a5a04d78ebf/.github/copilot-instructions.md?plain=1#L31

@RussKie why not use Moq?

Meir017 avatar May 07 '25 18:05 Meir017

why not use Moq?

Because it's no longer OSS-friendly.

RussKie avatar May 07 '25 23:05 RussKie