Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Aspire to łańcuch narzędzi do budowania, uruchamiania, debugowania i wdrażania aplikacji rozproszonych. Integracja z Aspire Azure Functions pozwala rozwijać, debugować i orkiestrować projekt Azure Functions jako część Aspire AppHost. Przykłady .NET w tym artykule wykorzystują model izolowanego pracownika.
Wymagania wstępne
Skonfiguruj środowisko programistyczne na potrzeby korzystania z usługi Azure Functions z aplikacją Aspire:
Zainstaluj wymagania wstępne Aspire, w tym wymagane przez Twój AppHost SDK .NET.
Zainstaluj integrację hostingową Aspire Azure Functions z katalogu AppHost.
aspire add Aspire.Hosting.Azure.FunctionsZainstaluj narzędzia Azure Functions Core Tools.
Jeśli korzystasz z Visual Studio, zainstaluj najnowsze aktualizacje narzędzi Visual Studio i Azure Functions:
- Przejdź do Narzędzia>Opcje.
- W obszarze Projekty i rozwiązania wybierz pozycję Azure Functions.
- Wybierz pozycję Sprawdź dostępność aktualizacji i zainstaluj aktualizacje zgodnie z monitem.
Więcej informacji o pakiecie integracyjnym i obsługiwanych API AppHost znajdziesz w artykule Ustaw Azure Functions w AppHost.
Struktura rozwiązania
Rozwiązanie korzystające z Azure Functions i Aspire składa się z wielu projektów, w tym AppHost oraz jednego lub więcej projektów Functions.
AppHost jest punktem wejścia do Twojej aplikacji. Organizuje ona konfigurację składników aplikacji, w tym projekt usługi Functions.
Rozwiązanie zwykle zawiera również projekt ustawień domyślnych usługi. Ten projekt udostępnia zestaw domyślnych usług i konfiguracji, które mają być używane w projektach w aplikacji.
Projekt AppHost
Aby pomyślnie skonfigurować integrację, upewnij się, że projekt AppHost spełnia następujące wymagania:
- AppHost odwołuje się do Aspire.Hosting.Azure.Functions. Ten pakiet definiuje integrację.
- AppHost języka C# odwołuje się do projektu Functions i wywołuje
AddAzureFunctionsProject<TProject>()lub wywołujeAddAzureFunctionsProject(name, projectPath)ze ścieżką do pliku projektu. Hosty aplikacji TypeScript AppHost używają formatuaddAzureFunctionsProjectproject-path. - Użyj
AddAzureFunctionsProjectzamiastAddProject. Projekt Functions dodany za pomocąAddProjectnie może zostać poprawnie uruchomiony.
Poniższy przykład przedstawia minimalny plik AppHost.cs dla projektu AppHost w języku C#:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject");
builder.Build().Run();
Projekt usługi Azure Functions
Aby pomyślnie skonfigurować integrację, upewnij się, że projekt usługi Azure Functions spełnia następujące wymagania:
Celuj w .NET 8 lub nowszy, użyj SDK .NET 9 lub nowszego oraz użyj modelu izolowanego pracownika.
Dodaj odwołania do Microsoft.Azure.Functions.Worker, Microsoft.Azure.Functions.Worker.Sdk oraz, w przypadku wyzwalaczy HTTP, Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.
Plik
Program.csmusi używać wersjiIHostApplicationBuilderrozruchu instancji hosta. To wymaganie oznacza, że należy użyć poleceniaFunctionsApplication.CreateBuilder(args).Jeśli twoje rozwiązanie zawiera projekt domyślny usługi, upewnij się, że projekt usługi Functions jest skonfigurowany do korzystania z niego:
- Projekt Functions powinien zawierać odwołanie do projektu domyślnych ustawień serwisu.
- Przed skompilowaniem
IHostApplicationBuilderwProgram.csuwzględnij wywołaniebuilder.AddServiceDefaults().
W poniższym przykładzie pokazano minimalny plik Program.cs dla projektu Functions używanego w Aspire.
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Hosting;
var builder = FunctionsApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.ConfigureFunctionsWebApplication();
builder.Build().Run();
Ten przykład nie zawiera domyślnej konfiguracji usługi Application Insights, która jest wyświetlana w wielu innych Program.cs przykładach i w szablonach usługi Azure Functions. Zamiast tego konfigurujesz integrację OpenTelemetry w Aspire, wywołując metodę builder.AddServiceDefaults().
Aby jak najlepiej wykorzystać integrację, należy wziąć pod uwagę następujące wytyczne:
- Nie uwzględniaj żadnych bezpośrednich integracji usługi Application Insights w projekcie usługi Functions. Monitorowanie w Aspire jest obsługiwane za pośrednictwem OpenTelemetry. Możesz skonfigurować Aspire do eksportowania danych do Azure Monitor poprzez projekt domyślnych ustawień usługi.
- Gdy Aspire uruchamia projekt Functions, należy preferować ustawienia przekazywane przez AppHost. Możesz zachować odpowiednie ustawienia w
local.settings.json, aby uruchamiać projekt niezależnie za pomocąfunc start; zmienne środowiskowe wstrzykiwane przez Aspire zastąpią je.
Konfiguracja połączenia z aplikacją Aspire
AppHost definiuje zasoby i pomaga tworzyć połączenia między nimi za pomocą kodu. W tej sekcji przedstawiono sposób konfigurowania i dostosowywania połączeń używanych przez projekt usługi Azure Functions.
Aspire zawiera domyślne uprawnienia do połączeń, które mogą pomóc w rozpoczęciu pracy. Jednak te uprawnienia mogą nie być odpowiednie lub wystarczające dla aplikacji.
W przypadku scenariuszy korzystających z kontroli dostępu opartej na rolach (RBAC) platformy Azure można dostosować uprawnienia, wywołując metodę WithRoleAssignments() w zasobie projektu. Po wywołaniu WithRoleAssignments() wszystkie domyślne przypisania ról zostaną usunięte i należy jawnie zdefiniować wszystkie przypisania ról, które chcesz. Jeśli hostujesz aplikację w usłudze Azure Container Apps, użycie WithRoleAssignments() również wymaga wywołania AddAzureContainerAppEnvironment() na DistributedApplicationBuilder.
Pamięć hosta dla Azure Functions
Usługa Azure Functions wymaga połączenia magazynu hosta (AzureWebJobsStorage) dla kilku podstawowych zachowań. Gdy wywołujesz AddAzureFunctionsProject<TProject>() w swoim AppHost, domyślnie tworzysz połączenie AzureWebJobsStorage i przekazujesz je do projektu Functions. To domyślne połączenie korzysta z emulatora Azure Storage do lokalnych uruchomieni programistycznych i automatycznie alokuje konto pamięci masowej podczas wdrożenia. Aby uzyskać większą kontrolę, zastąp to połączenie, wywołując .WithHostStorage() na zasobie projektu Functions.
Domyślne uprawnienia, które Aspire ustawia dla połączenia z pamięcią hosta, zależą od tego, czy wywołasz WithHostStorage() , czy nie. Dodanie WithHostStorage() usuwa przypisanie uczestnika konta magazynu. Aspire ustawia domyślne uprawnienia dla połączenia pamięci masowej hosta w poniższej tabeli.
| Połączenie pamięci masowej hosta | Role domyślne |
|---|---|
Brak połączenia z WithHostStorage() |
Współautor danych obiektu blob usługi Storage, Współautor danych kolejki usługi Storage, Kontrybutor danych tabeli Storage Współpracownik konta magazynowego |
Wywołanie WithHostStorage() |
Współautor danych obiektu blob usługi Storage, Współautor danych kolejki usługi Storage, Współautor danych tabeli usługi Storage |
Poniższy przykład przedstawia minimalny plik AppHost.cs, który zastępuje magazyn hosta i określa przypisanie roli:
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();
Note
Właściciel danych obiektu blob usługi Storage jest rolą zalecaną dla podstawowych potrzeb połączenia magazynu hosta. Aplikacja może napotkać problemy, jeśli połączenie z usługą blob ma tylko domyślną rolę Aspire Storage Blob Data Contributor.
W przypadku scenariuszy produkcyjnych należy uwzględnić wywołania zarówno do WithHostStorage(), jak i WithRoleAssignments(). Następnie możesz jawnie ustawić tę rolę wraz ze wszystkimi innymi, których potrzebujesz.
Wyzwalanie i wiązanie połączeń
Mechanizmy wyzwalające i powiązania odwołują się do połączeń według ich nazw. Następujące integracje Aspire umożliwiają te połączenia poprzez wywołanie zasobu projektu WithReference():
| Integracja z Aspire | Role domyślne |
|---|---|
| Azure Blob Storage |
Współautor danych obiektu blob usługi Storage, Współautor danych kolejki usługi Storage, Współautor danych tabeli usługi Storage |
| Azure Queue Storage |
Współautor danych obiektu blob usługi Storage, Współautor danych kolejki usługi Storage, Współautor danych tabeli usługi Storage |
| Azure Event Hubs | Właściciel danych usługi Azure Event Hubs |
| Azure Service Bus | Właściciel danych usługi Azure Service Bus |
Poniższy przykład pokazuje minimalny AppHost.cs plik konfigurujący wyzwalacz kolejki. W tym przykładzie odpowiedni wyzwalacz kolejki ma właściwość Connection ustawioną na MyQueueTriggerConnection, więc wywołanie WithReference() określa nazwę.
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();
W przypadku innych integracji wywołania do WithReference ustawiają konfigurację w inny sposób. Udostępniają konfigurację dla integracji klienta Aspire, ale nie dla wyzwalaczy i powiązań. W przypadku tych integracji wywołaj metodę WithEnvironment() , aby przekazać informacje o połączeniu wyzwalacza lub powiązania w celu rozwiązania problemu.
W poniższym przykładzie pokazano, jak ustawić zmienną środowiskową MyBindingConnection dla zasobu, który uwidacznia wyrażenie parametrów połączenia:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection", otherIntegration.Resource.ConnectionStringExpression);
Jeśli chcesz, aby zarówno integracje klientów Aspire, jak i system wyzwalaczy oraz powiązań używać połączenia, możesz skonfigurować zarówno WithReference(), jak i WithEnvironment().
W przypadku niektórych zasobów struktura połączenia może się różnić w przypadku uruchamiania go lokalnie i podczas publikowania go na platformie Azure. W poprzednim przykładzie otherIntegration może to być zasób, który działa jako emulator, więc ConnectionStringExpression zwraca parametry połączenia emulatora. Jednak po opublikowaniu zasobu Aspire może ustanowić połączenie oparte na tożsamości i ConnectionStringExpression zwróci identyfikator URI usługi. W takim przypadku, aby skonfigurować połączenia oparte na tożsamości dla usługi Azure Functions, może być konieczne podanie innej nazwy zmiennej środowiskowej.
W poniższym przykładzie użyto builder.ExecutionContext.IsPublishMode do warunkowego dodania niezbędnego sufiksu.
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection" + (builder.ExecutionContext.IsPublishMode ? "__serviceUri" : ""), otherIntegration.Resource.ConnectionStringExpression);
Aby uzyskać szczegółowe informacje na temat formatów połączeń, które obsługuje każde powiązanie, oraz uprawnienia wymagane przez te formaty, zapoznaj się ze stronami referencyjnymi powiązania.
Aby uzyskać więcej informacji o tym, jak kod Functions odczytuje wartości wstrzyknięte przez WithReference, zobacz konfigurację wykonawczą Azure Functions.
Hostowanie aplikacji
Aspire wspiera wdrażanie Azure Container Apps dla projektów Functions. Możesz także użyć oddzielnej integracji App Service w wersji zapoznawczej, aby określić jako docelową aplikację funkcji obsługującą kontenery:
- Wdrażaj jako aplikację kontenerową
- Wdróż jako aplikację funkcji, używając integracji App Service w wersji zapoznawczej
W obu przypadkach projekt jest wdrażany jako kontener. Aspire zajmuje się tworzeniem obrazu kontenera i wypychaniem go do Azure Container Registry.
Wdrażaj jako aplikację kontenerową
Gdy twój AppHost jest przeznaczony dla Azure Container Apps, Aspire konfiguruje reguły skalowania dla projektu Functions przy użyciu KEDA. Korzystając z Azure Container Apps, musisz przeprowadzić dodatkową konfigurację kluczy funkcji. Więcej informacji można znaleźć w artykule Klucze dostępu w Azure Container Apps.
Wdroż skonfigurowany AppHost, uruchamiając aspire deploy. Więcej informacji można znaleźć w Deploy to Azure Container Apps oraz aspire deploy.
Klucze dostępu w usłudze Azure Container Apps
Kilka scenariuszy usługi Azure Functions używa kluczy dostępu, aby zapewnić podstawowe środki zaradcze przed niepożądanym dostępem. Na przykład funkcje wyzwalacza HTTP domyślnie wymagają wywołania klucza dostępu, chociaż to wymaganie można wyłączyć przy użyciu AuthLevel właściwości . Zobacz Praca z kluczami dostępu w usłudze Azure Functions, aby zapoznać się ze scenariuszami, które mogą wymagać klucza.
Gdy wdrażasz projekt Functions za pomocą Aspire do Azure Container Apps, system nie tworzy automatycznie ani nie zarządza kluczami dostępu do Functions. Jeśli musisz używać kluczy dostępu, możesz nimi zarządzać w ramach konfiguracji AppHost. Ta sekcja pokazuje, jak stworzyć metodę rozszerzenia, którą możesz wywołać z pliku AppHost, AppHost.cs aby tworzyć i zarządzać kluczami dostępu. To podejście używa usługi Azure Key Vault do przechowywania kluczy i podpinania ich w aplikacji kontenerowej jako sekrety.
Note
To zachowanie opiera się na dostawcy sekretów ContainerApps, który wymaga wersji hosta Functions 4.1044.0 lub nowszej.
Te kroki wymagają wersji Bicep lub nowszej 0.38.3 . Wersję Bicep można sprawdzić, uruchamiając polecenie bicep --version w wierszu polecenia. Jeśli masz zainstalowany interfejs wiersza polecenia platformy Azure, możesz użyć az bicep upgrade polecenia , aby szybko zaktualizować aplikację Bicep do najnowszej wersji.
Dodaj do swojego projektu AppHost następujące pakiety NuGet:
Stwórz nową klasę w swoim projekcie AppHost i dołącz następujący kod:
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);
}
}
Następnie możesz użyć tej metody w pliku AppHosta AppHost.cs:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(storage)
.WithExternalHttpEndpoints()
.PublishWithContainerAppSecrets(systemKeyExtensionNames: ["mcp"]);
W tym przykładzie użyto domyślnego magazynu kluczy utworzonego przez metodę rozszerzenia. Skutkuje to kluczem domyślnym i kluczem systemowym dla rozszerzenia Protokołu kontekstu modelu.
Aby używać tych kluczy od klientów, należy pobrać je z magazynu kluczy.
Wdrażaj jako aplikację funkcyjną
Note
Wdrożenie jako aplikacja funkcjonalna wymaga integracji z Aspire Azure App Service, która jest obecnie w fazie podglądu.
Możesz skonfigurować Aspire do wdrażania do aplikacji funkcji za pomocą integracji Aspire z usługą Azure App Service. Ponieważ Aspire wdraża projekt Functions jako kontener, plan hostingu dla Twojej aplikacji Function musi wspierać wdrażanie aplikacji kontenerowych.
Aby wdrożyć swój projekt Aspire Functions jako aplikację funkcyjną, postępuj zgodnie z następującymi krokami:
- W katalogu AppHost uruchom
aspire add Aspire.Hosting.Azure.AppService, aby dodać pakiet NuGet Aspire.Hosting.Azure.AppService. - W pliku wywołaj
AppHost.csAddAzureAppServiceEnvironment()IDistributedApplicationBuilderwystąpienie, aby utworzyć plan usługi App Service. Należy pamiętać, że pomimo nazwy nie zapewnia to zasobu Środowiska Usług Aplikacyjnych (App Service Environment). - W zasobie projektu Functions wywołaj metodę
.WithExternalHttpEndpoints(). Jest to wymagane do wdrożenia z integracją Aspire Azure App Service. - W zasobach projektu Functions wywołaj
.PublishAsAzureAppServiceWebsite((infra, app) => app.Kind = "functionapp,linux"), aby dostosować ten projekt jako aplikację funkcjonalną w planie.
Important
Upewnij się, że ustawisz właściwość app.Kind na "functionapp,linux". To ustawienie gwarantuje, że zasób jest tworzony jako aplikacja funkcji, co wpływa na doświadczenie w pracy z aplikacją.
Poniższy przykład przedstawia minimalny plik AppHost.cs, który wdraża projekt usługi Functions jako aplikację funkcji:
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();
Ta konfiguracja tworzy plan Premium V3. W przypadku korzystania z dedykowanego planu usługi App Service SKU, skalowanie nie bazuje na zdarzeniach. Zamiast tego skalowanie jest zarządzane za pomocą ustawień planu usługi App Service.
Zagadnienia i najlepsze rozwiązania
Podczas oceniania integracji usługi Azure Functions z aplikacją Aspire należy wziąć pod uwagę następujące kwestie:
Konfiguracja wyzwalacza i wiązania za pośrednictwem platformy Aspire jest obecnie ograniczona do określonych integracji. Aby uzyskać szczegółowe informacje, zobacz Konfiguracja połączenia z aplikacją Aspire w tym artykule.
Plik projektu
Program.csfunkcji powinien używaćIHostApplicationBuilderwersji uruchamiania wystąpienia hosta. Korzystając zIHostApplicationBuilder, możesz użyćbuilder.AddServiceDefaults(), aby dodać domyślne ustawienia usług Aspire do projektu Functions.Aspire używa OpenTelemetry do monitorowania. Możesz skonfigurować Aspire do eksportowania danych do Azure Monitor poprzez projekt domyślnych ustawień usługi.
W wielu innych kontekstach usługi Azure Functions można uwzględnić bezpośrednią integrację z usługą Application Insights, rejestrując usługę roboczą. Nie rejestruj drugiego, bezpośredniego potoku Application Insights, jeśli używasz Aspire Service Defaults.
Dla projektów Functions wpisanych do orkiestracji Aspire, AppHost powinien zapewnić większość konfiguracji aplikacji. Możesz użyć
local.settings.jsondo samodzielnego uruchomienia projektu Functions za pomocąfunc start. Gdy Aspire uruchamia projekt, zmienne środowiskowe wstrzyknięte przez Aspire zastępują wartości o tych samych nazwach wlocal.settings.json.Unikaj uruchamiania drugiego emulatora Azure Storage dla połączeń, którymi zarządza AppHost. Konkurencyjne instancje emulatorów mogą powodować konflikty portów i pamięci masowej.
Więcej informacji można znaleźć w Azure Functions runtime configuration oraz Aspire telemetry.