Skip to content

Fix AzureBicepResource file-not-found error when using templateFile with AzurePublishingContext#13968

Merged
eerhardt merged 3 commits intomainfrom
copilot/fix-azure-bicep-file-error
Jan 20, 2026
Merged

Fix AzureBicepResource file-not-found error when using templateFile with AzurePublishingContext#13968
eerhardt merged 3 commits intomainfrom
copilot/fix-azure-bicep-file-error

Conversation

Copy link
Contributor

Copilot AI commented Jan 16, 2026

Description

AzureBicepResource with a templateFile parameter failed during AzurePublishingContext.WriteModelAsync() with "Could not find file" errors. GetBicepTemplateFile() combined paths without copying the file to the output directory

Changes:

  • GetBicepTemplateFile(): When a TemplateFile is specified, return it directly without combining the output directory path.
  • Test: Added AzureBicepResourceWithTemplateFile_CanBePublished to validate end-to-end publishing with template files

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
    • No
  • Does the change require an update in our Aspire docs?
    • Yes
    • No

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • aka.ms
    • Triggering command: /usr/local/bin/bicep /usr/local/bin/bicep build /tmp/aspire-bicepHgBrjy/env-acr.module.bicep --stdout (dns block)
    • Triggering command: /usr/local/bin/bicep /usr/local/bin/bicep build /tmp/aspire-bicepccCXB9/teststorage.module.bicep --stdout (dns block)
    • Triggering command: /usr/local/bin/bicep /usr/local/bin/bicep build /tmp/aspire-bicep8yq5hz/env.module.bicep --stdout (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Failed to write Azure Bicep templates: Could not find file with AzurePublishingContext</issue_title>
<issue_description>Using an AzureBicepResource with a template file and using AzurePublishingContext to publish all the bicep files, results in an exception:

12:59:32 (publish-custom) ✗ Failed to write Azure Bicep templates: Could not find file
'C:\Users\eerhardt\AppData\Local\Temp\aspire-bicepwqooyya3.vit\front-door-appservice.bicep'. (0.0s)
12:59:32 (publish-custom) ✗ [ERR] Failed to write Azure Bicep templates to
C:\Users\eerhardt\source\repos\AspireApp4\AspireApp4.AppHost\aspire-output\root\templates
12:59:32 (publish-custom) ✗ [ERR] Step 'publish-custom' failed.
12:59:32 (publish-custom) ✗ Step 'publish-custom' failed: Could not find file
'C:\Users\eerhardt\AppData\Local\Temp\aspire-bicepwqooyya3.vit\front-door-appservice.bicep'.
12:59:32 (pipeline-execution) ✗ [ERR] Step 'publish-custom' failed: Could not find file
'C:\Users\eerhardt\AppData\Local\Temp\aspire-bicepwqooyya3.vit\front-door-appservice.bicep'.
12:59:32 (pipeline-execution) ✗ Failed

Repo steps

aspire do pubilsh-custom the following AppHost:

#pragma warning disable ASPIREPIPELINES001
#pragma warning disable ASPIREPIPELINES004
#pragma warning disable ASPIREAZURE001

using Aspire.Hosting.Azure;
using Aspire.Hosting.Pipelines;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

var builder = DistributedApplication.CreateBuilder(args);

var apiService = builder.AddProject<Projects.AspireApp4_ApiService>("apiservice")
    .WithHttpHealthCheck("/health");

var frontend = builder.AddProject<Projects.AspireApp4_Web>("webfrontend")
    .WithExternalHttpEndpoints()
    .WithHttpHealthCheck("/health")
    .WithReference(apiService)
    .WaitFor(apiService);

builder.AddAzureFrontDoor("afd", frontend);

builder.Pipeline.AddStep("publish-custom", async context =>
{
    var outputPath = Path.Combine(context.Services.GetRequiredService<IPipelineOutputService>().GetOutputDirectory(), "root");
    var outputDirectory = new DirectoryInfo(outputPath);
    outputDirectory.Create();

    var templates = new DirectoryInfo(Path.Join(outputDirectory.FullName, "templates"));
    templates.Create();

    var azureProvisioningOptions = context.Services.GetRequiredService<IOptions<AzureProvisioningOptions>>().Value;

    var azPublishContext = new AzurePublishingContext(templates.FullName, azureProvisioningOptions, context.Services, context.Logger, context.ReportingStep);
    var azureEnvironmentResource = context.Model.Resources.OfType<AzureEnvironmentResource>().FirstOrDefault() ?? throw new InvalidOperationException("AzureEnvironmentResource not found in the model.");
    await azPublishContext.WriteModelAsync(context.Model, azureEnvironmentResource, context.CancellationToken).ConfigureAwait(false);
});

builder.Build().Run();

internal static class DeploymentExtensions
{
    public static IResourceBuilder<AzureBicepResource> AddAzureFrontDoor(
        this IDistributedApplicationBuilder builder,
        [ResourceName] string name,
        IResourceBuilder<ProjectResource> appServiceWebsite)
    {
        builder.AddAzureProvisioning();

        var frontDoorName = $"{name}-afd";
        var frontdoor = new AzureBicepResource(frontDoorName, "front-door-appservice.bicep");

        return builder.AddResource(frontdoor)
            .WithParameter("frontDoorName", frontDoorName)
            .WithParameter("appServiceHostName", appServiceWebsite.Resource.Name);
    }
}

with front-door-appservice.bicep:

param frontDoorName string
param appServiceHostName string

@description('Location for all resources, needed because Aspire always injects a location parameter')
param location string = resourceGroup().location

resource frontDoorProfile 'Microsoft.Cdn/profiles@2024-02-01' = {
  name: take('${frontDoorName}${uniqueString(resourceGroup().id)}', 50)
  location: 'Global'
  sku: {
    name: 'Premium_AzureFrontDoor'
  }
}

resource frontDoorEndpoint 'Microsoft.Cdn/profiles/afdEndpoints@2025-06-01' = {
  parent: frontDoorProfile
  name: take('${frontDoorName}-endp-${uniqueString(resourceGroup().id)}', 50)
  location: 'Global'
  properties: {
    enabledState: 'Enabled'
  }
}

resource originGroup 'Microsoft.Cdn/profiles/originGroups@2025-06-01' = {
  parent: frontDoorProfile
  name: take('appservice-origin-group-${uniqueString(resourceGroup().id)}', 50)
  properties: {
    loadBalancingSettings: {
      sampleSize: 4
      successfulSamplesRequired: 3
      additionalLatencyInMilliseconds: 50
    }
    healthProbeSettings: {
      probePath: '/'
      probeRequestType: 'HEAD'
      probeProtocol: 'Https'
      probeIntervalInSeconds: 240
    }
    sessionAffinityState: 'Disabled'
  }
}

resource origin 'Microsoft.Cdn/profiles/originGroups/origins@2025-06-01' = {
  parent: originGroup
  name: take('appservice-orig...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes dotnet/aspire#13967

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

- Convert relative template file paths to absolute in constructor
- Copy template files to output directory when directory parameter is provided
- Add test to verify bicep resources with template files can be published

Co-authored-by: eerhardt <8291187+eerhardt@users.noreply.github.com>
@github-actions
Copy link
Contributor

github-actions bot commented Jan 16, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 13968

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 13968"

Copilot AI changed the title [WIP] Fix Azure Bicep templates publishing error Fix AzureBicepResource file-not-found error when using templateFile with AzurePublishingContext Jan 16, 2026
Copilot AI requested a review from eerhardt January 16, 2026 19:28
@eerhardt eerhardt force-pushed the copilot/fix-azure-bicep-file-error branch from 0502f33 to a7e3a40 Compare January 17, 2026 00:10
- Don't combine paths if TemplateFile is specified
- Add test to verify bicep resources with template files can be published

Fix #13967
@eerhardt eerhardt force-pushed the copilot/fix-azure-bicep-file-error branch from a7e3a40 to eaa877c Compare January 17, 2026 00:11
@eerhardt eerhardt marked this pull request as ready for review January 17, 2026 00:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where AzureBicepResource with a templateFile parameter failed during Azure publishing with "Could not find file" errors. The issue occurred because GetBicepTemplateFile() incorrectly combined user-provided template file paths with a temporary directory parameter, resulting in invalid file paths when attempting to copy the template files.

Changes:

  • Modified GetBicepTemplateFile() to return the template file path directly when TemplateFile is specified, instead of combining it with the directory parameter
  • Added three unit tests to verify the corrected behavior of GetBicepTemplateFile() with template files vs template strings
  • Added an integration test to validate end-to-end publishing with relative template file paths

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/Aspire.Hosting.Azure/AzureBicepResource.cs Fixed GetBicepTemplateFile() to return TemplateFile path directly without incorrectly combining it with directory parameter
tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs Added three unit tests verifying GetBicepTemplateFile() behavior with template files and strings
tests/Aspire.Hosting.Azure.Tests/AzureEnvironmentResourceTests.cs Added integration test using RemoteExecutor to validate end-to-end publishing with relative template file paths

@eerhardt eerhardt merged commit 83cc418 into main Jan 20, 2026
308 of 309 checks passed
@eerhardt eerhardt deleted the copilot/fix-azure-bicep-file-error branch January 20, 2026 16:28
@dotnet-policy-service dotnet-policy-service bot added this to the 13.2 milestone Jan 20, 2026
@eerhardt
Copy link
Member

/backport to release/13.1

@github-actions
Copy link
Contributor

Started backporting to release/13.1: https://github.com/dotnet/aspire/actions/runs/21179320631

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants