microsoft / microsoft/aspire

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

Open
#7,330 5 comments 0 reactions 0 assignees View on GitHub
area-deployment azure silent-failure
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

### Is there an existing issue for this?

- [x] 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](https://github.com/user-attachments/files/18602166/aspire-manifest.json)

```bicep
@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:
```csharp
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();
```
2. 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_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.