Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f601838
Added initial support for app service as a compute environment
davidfowl May 3, 2025
75754d0
Rename AzureContainerAppExecutableExtensions to AzureAppServiceComput…
davidfowl May 3, 2025
d377bda
Add playground sample
davidfowl May 3, 2025
de11dd4
Enhance Azure App Service error messages and skip ignored resources i…
davidfowl May 3, 2025
2517e25
Refactor Azure Cosmos DB configuration to remove access key authentic…
davidfowl May 3, 2025
8584b0c
Remove Redis package references from Azure App Host project
davidfowl May 3, 2025
c12e359
Remove redis urls
davidfowl May 3, 2025
6990e1b
Refactor identity handling in Azure App Service environment extension…
davidfowl May 3, 2025
70ea39b
Remove unused parameter resolution logic for Azure Bicep resources in…
davidfowl May 3, 2025
bca9076
Refactor Key Vault secret handling to streamline resource allocation …
davidfowl May 3, 2025
94ef997
Added test or AsKeyVaultSecret
davidfowl May 5, 2025
d1f17a4
Normalize Key Vault name generation in AsKeyVaultSecret method for co…
davidfowl May 5, 2025
655962f
Update Key Vault secret URI handling to use non-versioned URIs for Ap…
davidfowl May 5, 2025
964202c
Add Azure Bicep modules and update App Service environment references…
davidfowl May 5, 2025
b2cceb5
Moved projects
davidfowl May 5, 2025
770945d
Update parameter names from 'id' to 'planid' for consistency in Bicep…
davidfowl May 5, 2025
2ed723d
Update PackageTags in project file for improved clarity and consistency
davidfowl May 5, 2025
3282b01
Fixed xml
davidfowl May 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Hosting.Azure.ContainerRegistry", "src\Aspire.Hosting.Azure.ContainerRegistry\Aspire.Hosting.Azure.ContainerRegistry.csproj", "{6CBA29C8-FF78-4ABC-BEFA-2A53CB4DB2A3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Hosting.Azure.AppService", "src\Aspire.Hosting.Azure.AppService\Aspire.Hosting.Azure.AppService.csproj", "{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AzureAppService", "AzureAppService", "{2D9974C2-3AB2-FBFD-5156-080508BB7449}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureAppService.ApiService", "playground\AzureAppService\AzureAppService.ApiService\AzureAppService.ApiService.csproj", "{A617DC84-65DA-41B5-B378-6C2F569CEE48}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureAppService.AppHost", "playground\AzureAppService\AzureAppService.AppHost\AzureAppService.AppHost.csproj", "{2C879943-DF34-44FA-B2C3-29D97F24DD76}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -3891,6 +3899,42 @@ Global
{6CBA29C8-FF78-4ABC-BEFA-2A53CB4DB2A3}.Release|x64.Build.0 = Release|Any CPU
{6CBA29C8-FF78-4ABC-BEFA-2A53CB4DB2A3}.Release|x86.ActiveCfg = Release|Any CPU
{6CBA29C8-FF78-4ABC-BEFA-2A53CB4DB2A3}.Release|x86.Build.0 = Release|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Debug|x64.ActiveCfg = Debug|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Debug|x64.Build.0 = Debug|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Debug|x86.ActiveCfg = Debug|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Debug|x86.Build.0 = Debug|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Release|Any CPU.Build.0 = Release|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Release|x64.ActiveCfg = Release|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Release|x64.Build.0 = Release|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Release|x86.ActiveCfg = Release|Any CPU
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941}.Release|x86.Build.0 = Release|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Debug|x64.ActiveCfg = Debug|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Debug|x64.Build.0 = Debug|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Debug|x86.ActiveCfg = Debug|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Debug|x86.Build.0 = Debug|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Release|Any CPU.Build.0 = Release|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Release|x64.ActiveCfg = Release|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Release|x64.Build.0 = Release|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Release|x86.ActiveCfg = Release|Any CPU
{A617DC84-65DA-41B5-B378-6C2F569CEE48}.Release|x86.Build.0 = Release|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Debug|x64.ActiveCfg = Debug|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Debug|x64.Build.0 = Debug|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Debug|x86.ActiveCfg = Debug|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Debug|x86.Build.0 = Debug|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Release|Any CPU.Build.0 = Release|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Release|x64.ActiveCfg = Release|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Release|x64.Build.0 = Release|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Release|x86.ActiveCfg = Release|Any CPU
{2C879943-DF34-44FA-B2C3-29D97F24DD76}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -4209,6 +4253,10 @@ Global
{8FCA0CFA-7823-6A2F-342A-107A994915B0} = {C424395C-1235-41A4-BF55-07880A04368C}
{30950CEB-2232-F9FC-04FF-ADDCB8AC30A7} = {C424395C-1235-41A4-BF55-07880A04368C}
{6CBA29C8-FF78-4ABC-BEFA-2A53CB4DB2A3} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{5DDF8E89-FBBD-4A6F-BF32-7D2140724941} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{2D9974C2-3AB2-FBFD-5156-080508BB7449} = {D173887B-AF42-4576-B9C1-96B9E9B3D9C0}
{A617DC84-65DA-41B5-B378-6C2F569CEE48} = {2D9974C2-3AB2-FBFD-5156-080508BB7449}
{2C879943-DF34-44FA-B2C3-29D97F24DD76} = {2D9974C2-3AB2-FBFD-5156-080508BB7449}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {47DCFECF-5631-4BDE-A1EC-BE41E90F60C4}
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<PackageVersion Include="Azure.Provisioning" Version="$(AzureProvisiongVersion)" />
<PackageVersion Include="Azure.Provisioning.AppConfiguration" Version="$(AzureProvisiongVersion)" />
<PackageVersion Include="Azure.Provisioning.AppContainers" Version="$(AzureProvisiongVersion)" />
<PackageVersion Include="Azure.Provisioning.AppService" Version="$(AzureProvisiongVersion)" />
<PackageVersion Include="Azure.Provisioning.ApplicationInsights" Version="$(AzureProvisiongVersion)" />
<PackageVersion Include="Azure.Provisioning.ContainerRegistry" Version="$(AzureProvisiongVersion)" />
<PackageVersion Include="Azure.Provisioning.CognitiveServices" Version="$(AzureProvisiongVersion)" />
Expand Down
3 changes: 3 additions & 0 deletions playground/AzureAppService/.aspire/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"appHostPath": "../AzureAppService.AppHost/AzureAppService.AppHost.csproj"
Copy link
Member

Choose a reason for hiding this comment

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

Should we add .aspire to a .gitignore?

I don't understand why this file is even required.

Copy link
Member Author

Choose a reason for hiding this comment

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

Nope, it should be checked in

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<AspireProjectOrPackageReference Include="Aspire.Azure.Storage.Blobs" />
<AspireProjectOrPackageReference Include="Aspire.Microsoft.EntityFrameworkCore.Cosmos" />
<ProjectReference Include="..\..\Playground.ServiceDefaults\Playground.ServiceDefaults.csproj" />
</ItemGroup>

</Project>
81 changes: 81 additions & 0 deletions playground/AzureAppService/AzureAppService.ApiService/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Azure.Storage.Blobs;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

builder.AddCosmosDbContext<TestCosmosContext>("account", "db");
builder.AddAzureBlobClient("blobs");

var app = builder.Build();

app.MapDefaultEndpoints();

app.MapGet("/", () =>
{
return Results.Content("""
<html>
<body>
<ul>
<li><a href="/blobs">Blobs</a></li>
<li><a href="/cosmos">Cosmos</a></li>
</ul>
</body>
</html>
""",
"text/html");
});

app.MapGet("/blobs", async (BlobServiceClient bsc) =>
{
var container = bsc.GetBlobContainerClient("mycontainer");
await container.CreateIfNotExistsAsync();

var blobNameAndContent = Guid.NewGuid().ToString();
await container.UploadBlobAsync(blobNameAndContent, new BinaryData(blobNameAndContent));

var blobs = container.GetBlobsAsync();

var blobNames = new List<string>();

await foreach (var blob in blobs)
{
blobNames.Add(blob.Name);
}

return blobNames;
});

app.MapGet("/cosmos", async (TestCosmosContext context) =>
{
await context.Database.EnsureCreatedAsync();

context.Entries.Add(new EntityFrameworkEntry());
await context.SaveChangesAsync();

return await context.Entries.ToListAsync();
});

app.Run();

public class Entry
{
[JsonProperty("id")]
public string? Id { get; set; }
}

public class TestCosmosContext(DbContextOptions<TestCosmosContext> options) : DbContext(options)
{
public DbSet<EntityFrameworkEntry> Entries { get; set; }
}

public class EntityFrameworkEntry
{
public Guid Id { get; set; } = Guid.NewGuid();
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5193",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>9dc69458-f2b4-4306-9dc5-f7b8e398a3a9</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\..\KnownResourceNames.cs" Link="KnownResourceNames.cs" />
</ItemGroup>

<ItemGroup>
<AspireProjectOrPackageReference Include="Aspire.Hosting.Azure.AppService" />
<AspireProjectOrPackageReference Include="Aspire.Hosting.Azure.CosmosDB" />
<AspireProjectOrPackageReference Include="Aspire.Hosting.Azure.Storage" />
<AspireProjectOrPackageReference Include="Aspire.Hosting.AppHost" />

<ProjectReference Include="..\AzureAppService.ApiService\AzureAppService.ApiService.csproj" />
</ItemGroup>

</Project>
57 changes: 57 additions & 0 deletions playground/AzureAppService/AzureAppService.AppHost/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma warning disable ASPIREACADOMAINS001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

using Aspire.Hosting.Azure;
using Azure.Provisioning.Storage;

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAppServiceEnvironment("infra");

// Testing secret parameters
var param = builder.AddParameter("secretparam", "fakeSecret", secret: true);

// Testing kv secret refs
var cosmosDb = builder.AddAzureCosmosDB("account")
.RunAsEmulator(c => c.WithLifetime(ContainerLifetime.Persistent));

cosmosDb.AddCosmosDatabase("db");

// Testing managed identity
var storage = builder.AddAzureStorage("storage")
.ConfigureInfrastructure(infra =>
{
var storage = infra.GetProvisionableResources().OfType<StorageAccount>().Single();
storage.AllowBlobPublicAccess = false;
})
.RunAsEmulator(c => c.WithLifetime(ContainerLifetime.Persistent));
var blobs = storage.AddBlobs("blobs");

// Testing projects
builder.AddProject<Projects.AzureAppService_ApiService>("api")
.WithExternalHttpEndpoints()
.WithReference(blobs)
.WithRoleAssignments(storage, StorageBuiltInRole.StorageBlobDataContributor)
.WithReference(cosmosDb)
.WithEnvironment("VALUE", param)
.WithEnvironment(context =>
{
if (context.Resource.TryGetLastAnnotation<AppIdentityAnnotation>(out var identity))
{
context.EnvironmentVariables["AZURE_PRINCIPAL_NAME"] = identity.IdentityResource.PrincipalName;
}
});

#if !SKIP_DASHBOARD_REFERENCE
// This project is only added in playground projects to support development/debugging
// of the dashboard. It is not required in end developer code. Comment out this code
// or build with `/p:SkipDashboardReference=true`, to test end developer
// dashboard launch experience, Refer to Directory.Build.props for the path to
// the dashboard binary (defaults to the Aspire.Dashboard bin output in the
// artifacts dir).
builder.AddProject<Projects.Aspire_Dashboard>(KnownResourceNames.AspireDashboard);
#endif

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:15687;http://localhost:15688",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:16167",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:17317",
"ASPIRE_SHOW_DASHBOARD_RESOURCES": "true"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15688",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16167",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:17318",
"ASPIRE_SHOW_DASHBOARD_RESOURCES": "true",
"ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true"
}
},
"generate-manifest": {
"commandName": "Project",
"launchBrowser": true,
"dotnetRunMessages": true,
"commandLineArgs": "--publisher manifest --output-path aspire-manifest.json",
"applicationUrl": "http://localhost:15888",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16157"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
<IsPackable>true</IsPackable>
<PackageTags>aspire integration hosting azure</PackageTags>
Copy link
Member

Choose a reason for hiding this comment

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

Do we want any package tags specific for AppService?

<Description>Azure app service resource types for .NET Aspire.</Description>
<PackageIconFullPath>$(SharedDir)Azure_256x.png</PackageIconFullPath>
Copy link
Member

Choose a reason for hiding this comment

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

Does app service have its own icon?

<SuppressFinalPackageVersion>true</SuppressFinalPackageVersion>
</PropertyGroup>

<ItemGroup>
<Compile Include="$(SharedDir)BicepFunction2.cs" Link="Provisioning\Utils\BicepFunction2.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Azure.Provisioning.AppService" />
<PackageReference Include="Azure.Provisioning.ContainerRegistry" />
<ProjectReference Include="..\Aspire.Hosting.Azure\Aspire.Hosting.Azure.csproj" />
<ProjectReference Include="..\Aspire.Hosting.Azure.ContainerRegistry\Aspire.Hosting.Azure.ContainerRegistry.csproj" />
</ItemGroup>

</Project>
Loading