App Host
The Aspire App Host project is used to define and orchestrate all the infrastructure in one project.
This page gives an overview on how the app host works and is utilised for ProvEn 2. For full documentation, refer to the Aspire documentation.
Parameters
Section titled “Parameters”Aspire can take in parameters from the external environment. If no value is given, the app host will prompt for these before resources that depend on them are started. These are cached once provided.
Secrets are stored in the .NET user secrets store against the project.
Compute environment
Section titled “Compute environment”ProvEn 2.0 uses the Azure App Service compute environment, which instructs Aspire to create an App Service Plan and attach all web apps to this.
Dependencies
Section titled “Dependencies”Each Azure resource that is required is defined in the app host.
Where an emulator is available, RunAsEmulator is used.
In some cases, infrastructure is configured to tweak the default deployment settings.
Service bus queues must be manually defined. Storage containers/queues/tables are currently not definable in the app host and must instead be defined in the Bicep.
Event Grid
Section titled “Event Grid”Aspire does not currently offer an integration for Azure Event Grid Topics. Instead, this is defined as a Bicep template and imported into the App Host.
The App Host passes the input parameters, and has access to the template’s output parameters as normal.
Locally, a non-official emulator by Workleap is used and run as a container.
Configuration for this can be found in <AppHost>/infra/EventGridEmulator.json,
and changes to the config are hot-loaded.
Projects
Section titled “Projects”Each project is added with references to each of its dependencies. When a dependency must be running before the project starts, this is defined here.
Aspire automatically handles networking and connection strings (environment variables). Additional environment variables are defined here.
Aspire will create and assign a user-assigned managed identity for each project, and assign RBAC roles to each identity based on the dependencies. These are overridden or supplemented where appropriate.
Name resolution
Section titled “Name resolution”Aspire’s default name resolution is replaced by means of a custom ‘infrastructure resolver’
to comply with Core’s Azure resource naming scheme.
This can be found in CoreResourceNamePropertyResolver.
If a resource type is used but not mapped, a NotImplementedException will be thrown with the resource class name.
A mapping must be added to the GetTemplate method.
Bicep expressions
Section titled “Bicep expressions”In some cases, the Bicep generated by Aspire needs to be controlled more dynamically than the host can offer. We work around this by creating Bicep expressions directly in C#. This is messy and unideal, but does the job for now.
For example, the following function returns an expression:
FunctionCallExpression RgContains(string subStr) => new( new IdentifierExpression("contains"), BicepFunction.GetResourceGroup().Name.Compile(), subStr);
var isProd = RgContains("-prod");This is compiled to the following Bicep:
contains(resourceGroup().name, '-prod'))Service Defaults
Section titled “Service Defaults”A separate project included in the main solution named ServiceDefaults provides a default startup configuration
which can be used by any ASP.NET/Azure Functions solution.
These focus primarily on Aspire integration, while additionally providing some sensible integrations. This includes:
- OpenTelemetry and Application Insights
- Health checks
- Service discovery
- HTTP client defaults (including service discovery)
Any applications should call builder.AddServiceDefaults() at the start of their Program.cs file.