Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aspire incorrectly merges Azurite emulator bindings into production manifest, causing Bicep failure #7330

Open
1 task done
pfo-omicsstudio opened this issue Jan 30, 2025 · 4 comments
Labels
area-integrations Issues pertaining to Aspire Integrations packages azure Issues associated specifically with scenarios tied to using Azure
Milestone

Comments

@pfo-omicsstudio
Copy link

pfo-omicsstudio commented Jan 30, 2025

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Environment:

  • Aspire Version: 9.0.0 (tested on 1/30/2025)
  • .NET Version: .NET 9.0.102 SDK
  • Azure Dev CLI (azd): 1.11.1
  • OS: macOS (Apple Silicon)

When using Aspire with Azurite in development (RunAsEmulator) and Azure Storage in production (azd provision), Aspire incorrectly merges emulator bindings into the production manifest and Bicep templates.

This results in an invalid connection string containing bindings.blob.host, causing Bicep generation to fail with:

ERROR: generating bicep from manifest: evaluating value for ConnectionStrings__blobs: evaluating connection string for blobs: unsupported property referenced in binding expression: bindings.blob.host for azure.bicep.v0

What I Expected

  • In development, Aspire should correctly use Azurite.
  • In production, Aspire should generate a valid Azure Storage endpoint.
  • The production manifest/Bicep should not reference bindings.blob.host.

What Actually Happens

  • The emulator binding is incorrectly merged into the production manifest, causing bindings.blob.host to be present in production.
  • This results in Bicep generation failure, blocking deployment.

I have thoroughly reviewed my setup and compared it with other Aspire projects that use a similar configuration without issues. Despite my efforts, I have been unable to find any relevant documentation or discussions about this specific error. Given the lack of available solutions and my unsuccessful attempts at resolving the issue, I am unsure if this is a misconfiguration on my part or a potential bug. Any guidance or clarification would be greatly appreciated.

Below is the generated Aspire.NET manifest and Bicep file produced when running dotnet run --launch-profile manifest.

aspire-manifest.json

@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param principalId string

param principalType string

resource storage 'Microsoft.Storage/storageAccounts@2024-01-01' = {
  name: take('storage${uniqueString(resourceGroup().id)}', 24)
  kind: 'StorageV2'
  location: location
  sku: {
    name: 'Standard_GRS'
  }
  properties: {
    accessTier: 'Hot'
    allowSharedKeyAccess: false
    minimumTlsVersion: 'TLS1_2'
    networkAcls: {
      defaultAction: 'Allow'
    }
  }
  tags: {
    'aspire-resource-name': 'storage'
  }
}

resource blobs 'Microsoft.Storage/storageAccounts/blobServices@2024-01-01' = {
  name: 'default'
  parent: storage
}

resource storage_StorageBlobDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storage.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')
    principalType: principalType
  }
  scope: storage
}

resource storage_StorageTableDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storage.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')
    principalType: principalType
  }
  scope: storage
}

resource storage_StorageQueueDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storage.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')
    principalType: principalType
  }
  scope: storage
}

output blobEndpoint string = storage.properties.primaryEndpoints.blob

output queueEndpoint string = storage.properties.primaryEndpoints.queue

output tableEndpoint string = storage.properties.primaryEndpoints.table

Expected Behavior

  • In production, Aspire should not include any emulator host/port references.
  • The generated manifest/Bicep for production should only contain a valid Azure Blob Storage endpoint or connection string, not bindings.blob.host.

Actual Behavior

  • Aspire merges the emulator binding into the Bicep for production, causing the bindings.blob.host reference and resulting deployment failures.

Workarounds Attempted

  1. Separate resource names for dev vs. prod.

  2. Manual cleanup of old artifacts and caches.

  3. Explicit environment checks to ensure CI is not recognized

Steps To Reproduce

My setup is extremely simple. I simply did the following:

  1. Create a .NET Aspire project with the following code in AppHost:
var builder = DistributedApplication.CreateBuilder(args);

var storage = builder
    .AddAzureStorage("storage")
    .RunAsEmulator(resourceBuilder =>
    {
        resourceBuilder.WithDataVolume("omics-studio-storage-data");
        resourceBuilder.WithBlobPort(10000);
        resourceBuilder.WithLifetime(ContainerLifetime.Persistent);
    })
    .WithAnnotation(
        new ContainerImageAnnotation
        {
            Registry = "mcr.microsoft.com",
            Image = "azure-storage/azurite",
            Tag = "latest",
        }
    )
    .AddBlobs("blobs");

await builder.Build().RunAsync();
  1. Ran azd init and azd provision

And that gave me the following error:
generating bicep from manifest: evaluating value for ConnectionStrings__blobs: evaluating connection string for blobs: unsupported property referenced in binding expression: bindings.blob.host for azure.bicep.v0

Exceptions (if any)

generating bicep from manifest: evaluating value for ConnectionStrings__blobs: evaluating connection string for blobs: unsupported property referenced in binding expression: bindings.blob.host for azure.bicep.v0

.NET Version info

.NET SDK:
Version: 9.0.102
Commit: cb83cd4923
Workload version: 9.0.100-manifests.43af17c7
MSBuild version: 17.12.18+ed8c6aec5

Runtime Environment:
OS Name: Mac OS X
OS Version: 15.2
OS Platform: Darwin
RID: osx-arm64
Base Path: /usr/local/share/dotnet/sdk/9.0.102/

.NET workloads installed:
There are no installed workloads to display.
Configured to use loose manifests when installing new manifests.

Host:
Version: 9.0.1
Architecture: arm64
Commit: c8acea2262

.NET SDKs installed:
9.0.102 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 9.0.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 9.0.1 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
None

Environment variables:
Not set

global.json file:
Not found

Anything else?

No response

@pfo-omicsstudio pfo-omicsstudio changed the title bindings.blob.host Is Still Generated in Production When Using AddAzureStorage with Emulator in Development Aspire incorrectly merges Azurite emulator bindings into production manifest, causing Bicep failure Jan 30, 2025
@pfo-omicsstudio
Copy link
Author

A quick update on this. I tried rewriting the following code:

var storage = builder
    .AddAzureStorage("storage")
    .RunAsEmulator(resourceBuilder =>
    {
        resourceBuilder.WithDataVolume("omics-studio-storage-data");
        resourceBuilder.WithBlobPort(10000);
        resourceBuilder.WithLifetime(ContainerLifetime.Persistent);
    })
    .WithAnnotation(
        new ContainerImageAnnotation
        {
            Registry = "mcr.microsoft.com",
            Image = "azure-storage/azurite",
            Tag = "latest",
        }
    )
    .AddBlobs("blobs");

into this:

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

With this change, azd provision now works perfectly fine. However, this also means that the emulator is no longer running when developing locally, which is obviously not an actual solution.

Am I missing something here, or does this behavior seem unintuitive? Shouldn’t Aspire be smart enough to exclude the emulator configuration in production? What exactly is happening here?

@davidfowl
Copy link
Member

davidfowl commented Jan 30, 2025

Instead of manually adding annotations, the right approach is to use RunAsEmulator.

https://learn.microsoft.com/en-us/dotnet/aspire/storage/azure-storage-blobs-integration?tabs=dotnet-cli#add-azure-storage-emulator-resource

In that callback, you can change the image using WithImage* methods.

@davidfowl
Copy link
Member

var storage = builder
    .AddAzureStorage("storage")
    .RunAsEmulator(resourceBuilder =>
    {
        resourceBuilder.WithDataVolume("omics-studio-storage-data");
        resourceBuilder.WithBlobPort(10000);
        resourceBuilder.WithLifetime(ContainerLifetime.Persistent);
        resourceBuilder.WithImageTag("latest");
    })
    .AddBlobs("blobs");

@pfo-omicsstudio
Copy link
Author

Thank you so much @davidfowl! That worked and was exactly what I needed, and I apologize for any confusion.
Really appreciate the help, it means a lot 🙏

Do you think Aspire should include a failsafe to prevent this issue? The error message wasn’t very intuitive, and I struggled to find any relevant information online. It seems likely that others might run into the same problem in the future.

@sebastienros sebastienros added the area-integrations Issues pertaining to Aspire Integrations packages label Feb 11, 2025
@sebastienros sebastienros added this to the Backlog milestone Feb 11, 2025
@eerhardt eerhardt added the azure Issues associated specifically with scenarios tied to using Azure label Feb 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-integrations Issues pertaining to Aspire Integrations packages azure Issues associated specifically with scenarios tied to using Azure
Projects
None yet
Development

No branches or pull requests

4 participants