Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Aspire is een toolchain voor het bouwen, uitvoeren, debuggen en uitrollen van gedistribueerde applicaties. De Aspire Azure Functions-integratie stelt je in staat om een Azure Functions-project te ontwikkelen, te debuggen en te orkestreren als onderdeel van een Aspire AppHost. De .NET-voorbeelden in dit artikel gebruiken het model van geïsoleerde werker.
Prerequisites
Stel uw ontwikkelomgeving in voor het gebruik van Azure Functions met Aspire:
Installeer de Aspire-vereisten, waaronder de .NET SDK die vereist is voor uw AppHost.
Installeer de Aspire Azure Functions hostingintegratie vanuit de AppHost-map.
aspire add Aspire.Hosting.Azure.FunctionsInstalleer de Azure Functions Core Tools.
Als je Visual Studio gebruikt, installeer dan de nieuwste Visual Studio- en Azure Functions-tools-updates:
- Ga naar Extra-opties>.
- Selecteer Azure Functions onder Projecten en oplossingen.
- Selecteer Controleren op updates en installeer updates zoals hierom wordt gevraagd.
Voor meer informatie over het integratiepakket en de ondersteunde AppHost API's, zie Set up Azure Functions in de AppHost.
Oplossingsstructuur
Een oplossing die Azure Functions en Aspire gebruikt, heeft meerdere projecten, waaronder een AppHost en één of meer Functions-projecten.
De AppHost is het toegangspunt voor je aanvraag. Het organiseert de installatie van de onderdelen van uw toepassing, met inbegrip van het Functions-project.
De oplossing bevat doorgaans ook een standaardproject voor services . Dit project biedt een set standaardservices en configuraties die in projecten in uw toepassing moeten worden gebruikt.
AppHost-project
Om de integratie succesvol te configureren, zorg ervoor dat het AppHost-project aan de volgende eisen voldoet:
- De AppHost verwijst naar Aspire.Hosting.Azure. Functions. Dit pakket definieert de integratie.
- Een C# AppHost verwijst naar een Functions-project en roept
AddAzureFunctionsProject<TProject>()aan, of roeptAddAzureFunctionsProject(name, projectPath)aan met het pad naar het projectbestand. TypeScript AppHosts gebruiken de projectpadvorm vanaddAzureFunctionsProject. - Gebruik
AddAzureFunctionsProjectin plaats vanAddProject. Een Functions-project dat is toegevoegd door te gebruikenAddProject, kan niet goed starten.
Het volgende voorbeeld toont een minimaal AppHost.cs bestand voor een C# AppHost-project:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject");
builder.Build().Run();
Azure Functions-project
Als u de integratie wilt configureren, moet u ervoor zorgen dat het Azure Functions-project voldoet aan de volgende vereisten:
Target .NET 8 of later, gebruik de .NET 9 SDK of later, en gebruik het geïsoleerde worker-model.
Referentie Microsoft.Azure. Functions.Worker, Microsoft.Azure. Functions.Worker.Sdk, en, voor HTTP-triggers, Microsoft.Azure. Functions.Worker.Extensions.Http.AspNetCore.
Het
Program.csbestand moet deIHostApplicationBuilderversie van het opstart van de hostinstantie gebruiken. Deze vereiste betekent dat u moet gebruikenFunctionsApplication.CreateBuilder(args).Als uw oplossing een standaardproject voor services bevat, moet u ervoor zorgen dat uw Functions-project is geconfigureerd om het te gebruiken:
- Het Functions-project moet een projectreferentie naar het service-defaults-project bevatten.
- Voordat u
IHostApplicationBuilderinProgram.csbouwt, moet u een oproep naarbuilder.AddServiceDefaults()opnemen.
In het volgende voorbeeld ziet u een minimaal Program.cs bestand voor een Functions-project dat wordt gebruikt in Aspire:
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Hosting;
var builder = FunctionsApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.ConfigureFunctionsWebApplication();
builder.Build().Run();
Dit voorbeeld bevat niet de standaard Application Insights-configuratie die wordt weergegeven in veel andere Program.cs voorbeelden en in de Azure Functions-sjablonen. In plaats daarvan configureert u OpenTelemetry-integratie in Aspire door de methode aan te builder.AddServiceDefaults() roepen.
Bekijk de volgende richtlijnen om optimaal gebruik te maken van de integratie:
- Neem geen directe Application Insights-integraties op in het Functions-project. Bewaking in Aspire wordt in plaats daarvan afgehandeld via de OpenTelemetry-ondersteuning. U kunt Aspire configureren voor het exporteren van gegevens naar Azure Monitor via het standaardproject voor de service.
- Wanneer Aspire het Functions-project uitvoert, geef je voorkeur aan instellingen die door de AppHost zijn geïnjecteerd. Je kunt equivalente instellingen in
local.settings.jsonlaten staan om het project zelfstandig uit te voeren metfunc start; door Aspire geïnjecteerde omgevingsvariabelen hebben daar voorrang op.
Verbindingsconfiguratie met Aspire
De AppHost definieert resources en helpt je om verbindingen tussen deze te maken door gebruik te maken van code. In deze sectie wordt beschreven hoe u verbindingen configureert en aanpast die door uw Azure Functions-project worden gebruikt.
Aspire bevat standaard verbindingsmachtigingen die u kunnen helpen aan de slag te gaan. Deze machtigingen zijn echter mogelijk niet geschikt of voldoende voor uw toepassing.
Voor scenario's die gebruikmaken van op rollen gebaseerd toegangsbeheer van Azure (RBAC), kunt u machtigingen aanpassen door de WithRoleAssignments() methode voor de projectresource aan te roepen. Wanneer u aanroept WithRoleAssignments(), worden alle standaardroltoewijzingen verwijderd en moet u expliciet de volledige set roltoewijzingen definiëren die u wilt. Als u uw toepassing op Azure Container Apps host, moet u ook WithRoleAssignments() aanroepen op AddAzureContainerAppEnvironment() met behulp van DistributedApplicationBuilder.
Azure Functions-hostopslag
Azure Functions vereist een hostopslagverbinding (AzureWebJobsStorage) voor verschillende kerngedrag. Wanneer je AddAzureFunctionsProject<TProject>() in je AppHost aanroept, maak je standaard een verbinding van het type AzureWebJobsStorage aan en geef je die door aan het Functions-project. Deze standaardverbinding gebruikt de Azure Storage-emulator voor lokale ontwikkelingsruns en stelt automatisch een opslagaccount beschikbaar wanneer je het uitrolt. Voor meer controle vervang deze verbinding door de Functions-projectresource aan te roepen .WithHostStorage() .
De standaardrechten die Aspire voor de hostopslagverbinding stelt, hangen af van of je belt WithHostStorage() of niet. Het toevoegen van WithHostStorage() verwijdert een bijdrager voor opslagaccounts-toewijzing. De volgende tabel bevat de standaardmachtigingen die Aspire instelt voor de hostopslagverbinding:
| Hostopslagverbinding | Standaardrollen |
|---|---|
Geen telefoongesprek naar WithHostStorage() |
Bijdrager voor Blob-gegevensopslag, Inzender voor opslagwachtrijgegevens, Inzender voor opslagtabelgegevens, Bijdrager aan opslagaccount |
Roepen WithHostStorage() |
Bijdrager voor Blob-gegevensopslag, Inzender voor opslagwachtrijgegevens, Inzender voor opslagtabelgegevens |
Het volgende voorbeeld toont een minimaal AppHost.cs bestand dat de hostopslag vervangt en een roltoewijzing specificeert:
using Azure.Provisioning.Storage;
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureContainerAppEnvironment("myEnv");
var myHostStorage = builder.AddAzureStorage("myHostStorage");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(myHostStorage)
.WithRoleAssignments(myHostStorage, StorageBuiltInRole.StorageBlobDataOwner);
builder.Build().Run();
Opmerking
Eigenaar van opslagblobgegevens is de rol die wordt aanbevolen voor de basisbehoeften van de hostopslagverbinding. Uw app kan problemen ondervinden als de verbinding met de blobservice alleen de Aspire-standaard van Opslagblobgegevensbijdrager heeft.
Voor productiescenario's moet u zowel oproepen naar WithHostStorage() als WithRoleAssignments() opnemen. U kunt deze rol vervolgens expliciet instellen, samen met andere personen die u nodig hebt.
Trigger- en bindingsverbindingen
Uw triggers en bindingen verwijzen naar verbindingen op naam. De volgende Aspire-integraties bieden deze verbindingen via een aanroep naar WithReference() de projectresource:
| Ambieer integratie | Standaardrollen |
|---|---|
| Azure Blob-opslagruimte |
Bijdrager voor Blob-gegevensopslag, Inzender voor opslagwachtrijgegevens, Inzender voor opslagtabelgegevens |
| Azure Queue Storage |
Bijdrager voor Blob-gegevensopslag, Inzender voor opslagwachtrijgegevens, Inzender voor opslagtabelgegevens |
| Azure Event Hubs | Azure Event Hubs-gegevenseigenaar |
| Azure Service Bus | Eigenaar van Azure Service Bus-gegevens |
Het volgende voorbeeld toont een minimaal AppHost.cs bestand dat een wachtrijtrigger configureert. In dit voorbeeld is de eigenschap van de bijbehorende wachtrijtrigger ingesteld op Connection, dus specificeert de aanroep MyQueueTriggerConnection de naam.
var builder = DistributedApplication.CreateBuilder(args);
var myAppStorage = builder.AddAzureStorage("myAppStorage").RunAsEmulator();
var queues = myAppStorage.AddQueues("queues");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithReference(queues, "MyQueueTriggerConnection");
builder.Build().Run();
Voor andere integraties worden aanroepen om WithReference de configuratie op een andere manier in te stellen. Ze maken de configuratie beschikbaar voor Aspire-clientintegraties, maar niet voor triggers en bindingen. Voor deze integraties roept WithEnvironment() u om de verbindingsgegevens door te geven voor de trigger of binding die moet worden opgelost.
In het volgende voorbeeld ziet u hoe u de omgevingsvariabele MyBindingConnection instelt voor een resource waarmee een verbindingsreeksexpressie wordt weergegeven:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection", otherIntegration.Resource.ConnectionStringExpression);
Als u wilt dat zowel Aspire-clientintegraties als het systeem van triggers en bindingen een verbinding gebruiken, moet u zowel WithReference() als WithEnvironment() configureren.
Voor sommige resources kan de structuur van een verbinding verschillen tussen wanneer u deze lokaal uitvoert en wanneer u deze publiceert naar Azure. In het vorige voorbeeld otherIntegration kan dit een resource zijn die wordt uitgevoerd als een emulator, dus ConnectionStringExpression retourneert een emulatorverbindingsreeks. Wanneer de resource wordt gepubliceerd, kan Aspire echter een op identiteit gebaseerde verbinding instellen en ConnectionStringExpression de URI van de service retourneren. Als u in dit geval op identiteit gebaseerde verbindingen voor Azure Functions wilt instellen, moet u mogelijk een andere naam voor de omgevingsvariabele opgeven.
In het volgende voorbeeld wordt builder.ExecutionContext.IsPublishMode gebruikt om het benodigde achtervoegsel voorwaardelijk toe te voegen.
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection" + (builder.ExecutionContext.IsPublishMode ? "__serviceUri" : ""), otherIntegration.Resource.ConnectionStringExpression);
Raadpleeg de referentiepagina's van de binding voor meer informatie over de verbindingsindelingen die elke binding ondersteunt en de machtigingen die deze indelingen vereisen.
Voor meer informatie over hoe Functions-code waarden leest die worden geïnjecteerd door WithReference, zie Azure Functions runtime configuratie.
De toepassing hosten
Aspire ondersteunt Azure Container Apps-implementatie voor Functions-projecten. Je kunt ook de aparte preview App Service-integratie gebruiken om een container-geschikte functie-app te targeten:
- Implementeren als een container-app
- Implementeren als functie-app met de previewversie van de App Service-integratie
In beide gevallen wordt uw project geïmplementeerd als een container. Aspire zorgt ervoor dat de containerafbeeldingen voor u worden gebouwd en naar Azure Container Registry worden geüpload.
Implementeren als container-app
Wanneer je AppHost zich richt op Azure Container Apps, stelt Aspire schaalregels op voor je Functions-project met behulp van KEDA. Wanneer je Azure Container Apps gebruikt, moet je extra configuratie uitvoeren voor functiesleutels. Voor meer informatie, zie Access keys on Azure Container Apps.
Rol de geconfigureerde AppHost uit door te draaien aspire deploy. Voor meer informatie, zie Deploy to Azure Container Apps en aspire deploy.
Toegangssleutels in Azure Container Apps
In verschillende Azure Functions-scenario's worden toegangssleutels gebruikt om een basisbeperking te bieden tegen ongewenste toegang. Voor HTTP-triggerfuncties moet bijvoorbeeld standaard een toegangssleutel worden aangeroepen, hoewel deze vereiste kan worden uitgeschakeld met behulp van de AuthLevel eigenschap. Zie Werken met toegangssleutels in Azure Functions voor scenario's waarvoor mogelijk een sleutel is vereist.
Wanneer je een Functions-project uitrolt met Aspire naar Azure Container Apps, maakt of beheert het systeem niet automatisch toegangssleutels voor Functions. Als je toegangssleutels moet gebruiken, kun je ze beheren als onderdeel van je AppHost-setup. Deze sectie laat zien hoe je een extensiemethode kunt aanmaken die je vanuit het AppHost.cs bestand van je AppHost kunt aanroepen om toegangssleutels aan te maken en te beheren. Deze benadering maakt gebruik van Azure Key Vault om de sleutels op te slaan en deze als geheimen in de container-app te koppelen.
Opmerking
Het gedrag hier is afhankelijk van de ContainerApps geheime provider, die een Functions-hostversie 4.1044.0 of later vereist.
Voor deze stappen is Bicep-versie 0.38.3 of hoger vereist. U kunt uw Bicep-versie controleren door bicep --version uit te voeren vanuit een opdrachtprompt. Als u de Azure CLI hebt geïnstalleerd, kunt u met az bicep upgrade Bicep snel bijwerken naar de nieuwste versie.
Voeg de volgende NuGet-pakketten toe aan je AppHost-project:
Maak een nieuwe klasse aan in je AppHost-project en voeg de volgende code toe:
using Aspire.Hosting.Azure;
using Azure.Provisioning.AppContainers;
namespace Aspire.Hosting;
internal static class Extensions
{
private record SecretMapping(string OriginalName, IAzureKeyVaultSecretReference Reference);
public static IResourceBuilder<T> PublishWithContainerAppSecrets<T>(
this IResourceBuilder<T> builder,
IResourceBuilder<AzureKeyVaultResource>? keyVault = null,
string[]? hostKeyNames = null,
string[]? systemKeyExtensionNames = null)
where T : AzureFunctionsProjectResource
{
if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
return builder;
}
keyVault ??= builder.ApplicationBuilder.AddAzureKeyVault("functions-keys");
var hostKeysToAdd = (hostKeyNames ?? []).Append("default").Select(k => $"host-function-{k}");
var systemKeysToAdd = systemKeyExtensionNames?.Select(k => $"host-systemKey-{k}_extension") ?? [];
var secrets = hostKeysToAdd.Union(systemKeysToAdd)
.Select(secretName => new SecretMapping(
secretName,
CreateSecretIfNotExists(builder.ApplicationBuilder, keyVault, secretName.Replace("_", "-"))
)).ToList();
return builder
.WithReference(keyVault)
.WithEnvironment("AzureWebJobsSecretStorageType", "ContainerApps")
.PublishAsAzureContainerApp((infra, app) => ConfigureFunctionsContainerApp(infra, app, builder.Resource, secrets));
}
private static void ConfigureFunctionsContainerApp(
AzureResourceInfrastructure infrastructure,
ContainerApp containerApp,
IResource resource,
List<SecretMapping> secrets)
{
const string volumeName = "functions-keys";
const string mountPath = "/run/secrets/functions-keys";
var appIdentityAnnotation = resource.Annotations.OfType<AppIdentityAnnotation>().Last();
var containerAppIdentityId = appIdentityAnnotation.IdentityResource.Id.AsProvisioningParameter(infrastructure);
var containerAppSecretsVolume = new ContainerAppVolume
{
Name = volumeName,
StorageType = ContainerAppStorageType.Secret
};
foreach (var mapping in secrets)
{
var secret = mapping.Reference.AsKeyVaultSecret(infrastructure);
containerApp.Configuration.Secrets.Add(new ContainerAppWritableSecret()
{
Name = mapping.Reference.SecretName.ToLowerInvariant(),
KeyVaultUri = secret.Properties.SecretUri,
Identity = containerAppIdentityId
});
containerAppSecretsVolume.Secrets.Add(new SecretVolumeItem
{
Path = mapping.OriginalName.Replace("-", "."),
SecretRef = mapping.Reference.SecretName.ToLowerInvariant()
});
}
containerApp.Template.Containers[0].Value!.VolumeMounts.Add(new ContainerAppVolumeMount
{
VolumeName = volumeName,
MountPath = mountPath
});
containerApp.Template.Volumes.Add(containerAppSecretsVolume);
}
public static IAzureKeyVaultSecretReference CreateSecretIfNotExists(
IDistributedApplicationBuilder builder,
IResourceBuilder<AzureKeyVaultResource> keyVault,
string secretName)
{
var secretParameter = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"param-{secretName}", special: false);
builder.AddBicepTemplateString($"key-vault-key-{secretName}", """
param location string = resourceGroup().location
param keyVaultName string
param secretName string
@secure()
param secretValue string
// Reference the existing Key Vault
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyVaultName
}
// Deploy the secret only if it does not already exist
@onlyIfNotExists()
resource newSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
parent: keyVault
name: secretName
properties: {
value: secretValue
}
}
""")
.WithParameter("keyVaultName", keyVault.GetOutput("name"))
.WithParameter("secretName", secretName)
.WithParameter("secretValue", secretParameter);
return keyVault.GetSecret(secretName);
}
}
Je kunt dan deze methode gebruiken in het AppHost.cs bestand van je AppHost:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(storage)
.WithExternalHttpEndpoints()
.PublishWithContainerAppSecrets(systemKeyExtensionNames: ["mcp"]);
In dit voorbeeld wordt een standaardsleutelkluis gebruikt die is gemaakt met de extensiemethode. Dit resulteert in een standaardsleutel en een systeemsleutel voor gebruik met de extensie Model Context Protocol.
Als u deze sleutels van clients wilt gebruiken, moet u deze ophalen uit de sleutelkluis.
Implementeren als functie-app
Opmerking
Uitrollen als functionele app vereist de integratie van Aspire Azure App Service, die momenteel in preview is.
Je kunt Aspire configureren om te deployen naar een functie-app door gebruik te maken van de Aspire Azure App Service-integratie. Omdat Aspire het Functions-project als container uitrolt, moet het hostingplan voor je Function-app het uitrollen van containergeïntegreerde applicaties ondersteunen.
Om uw Aspire Functions-project als functionele app uit te rollen, volgt u deze stappen:
- Voer vanuit de AppHost-map
aspire add Aspire.Hosting.Azure.AppServiceuit om het Aspire.Hosting.Azure.AppService-NuGet-pakket toe te voegen. - Roep
AppHost.csin hetAddAzureAppServiceEnvironment()bestand uwIDistributedApplicationBuilderexemplaar aan om een App Service-plan te maken. Houd er rekening mee dat er, ondanks de naam, geen App Service Environment-resource wordt ingericht. - Gebruik de functies-projectresource om
.WithExternalHttpEndpoints()aan te roepen. Dit is vereist voor implementatie met de Integratie van Aspire Azure App Service. - Op de Functions-projectresource kunt u
.PublishAsAzureAppServiceWebsite((infra, app) => app.Kind = "functionapp,linux")aanroepen om dat project als functie-app binnen het plan te configureren.
Belangrijk
Zorg ervoor dat u de app.Kind eigenschap instelt op "functionapp,linux". Deze instelling zorgt ervoor dat de resource wordt gemaakt als een functie-app, wat van invloed is op ervaringen voor het werken met uw toepassing.
Het volgende voorbeeld toont een minimaal AppHost.cs bestand dat een Functions-project als een Function-app uitrolt:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureAppServiceEnvironment("functions-env");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithExternalHttpEndpoints()
.PublishAsAzureAppServiceWebsite((infra, app) => app.Kind = "functionapp,linux");
builder.Build().Run();
Met deze configuratie maakt u een Premium V3-abonnement. Wanneer u een toegewezen App Service-plan-SKU gebruikt, is het schalen niet gebeurtenis-gerelateerd. In plaats daarvan wordt schalen beheerd via de App Service-planinstellingen.
Overwegingen en beste praktijken
Houd rekening met de volgende punten wanneer u de integratie van Azure Functions met Aspire evalueert:
De trigger- en bindingsconfiguratie via Aspire is momenteel beperkt tot specifieke integraties. Zie de verbindingsconfiguratie met Aspire in dit artikel voor meer informatie.
Het
Program.csbestand van uw functieproject moet deIHostApplicationBuilderversie voor hostexemplaar-opstart gebruiken. Door te gebruikenIHostApplicationBuilderkun je aanroepenbuilder.AddServiceDefaults()om Aspire Service Defaults toe te voegen aan je Functions-project.Aspire maakt gebruik van OpenTelemetry voor bewaking. U kunt Aspire configureren voor het exporteren van gegevens naar Azure Monitor via het standaardproject voor de service.
In veel andere Azure Functions-contexten kunt u directe integratie met Application Insights opnemen door de werkrolservice te registreren. Registreer geen tweede, directe Application Insights-pijplijn wanneer je Aspire Service Defaults gebruikt.
Voor Functions-projecten die zijn opgenomen in een Aspire-orkestratie, zou de AppHost de meeste applicatieconfiguraties moeten verzorgen. Je kunt
local.settings.jsongebruiken om het Functions-project onafhankelijk uit te voeren metfunc start. Wanneer Aspire het project uitvoert, overschrijven door Aspire geïnjecteerde omgevingsvariabelen waarden met dezelfde namen inlocal.settings.json.Vermijd het starten van een tweede Azure Storage-emulator voor verbindingen die door de AppHost worden beheerd. Concurrerende emulator-instanties kunnen conflicten tussen poorten en opslag veroorzaken.
Voor meer informatie, zie Azure Functions runtime configuration en Aspire telemetry.