Intégration du stockage de file d’attente .NET AspireAzure
inclut :Intégration d'hébergement et intégration Client
Azure stockage file d’attente est un service permettant de stocker un grand nombre de messages accessibles à partir de n’importe où dans le monde via des appels authentifiés. L’intégration de stockage file d’attente .NET AspireAzure vous permet de vous connecter à des instances de stockage file d’attente existantes Azure ou de créer de nouvelles instances à partir d’applications .NET.
Intégration de l’hébergement
Le modèle d'intégration des ressources de stockage .NET.NET AspireAzure Storage représente les différentes ressources de stockage en tant que types suivants :
- AzureStorageResource: représente une ressource de stockage Azure.
- AzureStorageEmulatorResource: représente une ressource d’émulateur de stockage Azure (Azurite).
- AzureBlobStorageResource: Représente une ressource de stockage Blob Azure.
- AzureQueueStorageResource: représente une ressource de stockage de file d'attente Azure.
- AzureTableStorageResource: représente une ressource de stockage table Azure.
Pour accéder à ces types et API pour les exprimer, ajoutez le package NuGet 📦Aspire.Hébergement.Azure.Stockage dans le projet hôte de l'application .
dotnet add package Aspire.Hosting.Azure.Storage
Pour plus d’informations, consultez dotnet add package ou Gérer les dépendances de package dans les applications .NET.
Ajouter une ressource de stockage Azure
Dans votre projet hôte d’application, appelez AddAzureStorage pour ajouter et retourner un générateur de ressources de stockage Azure.
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage");
// An Azure Storage resource is required to add any of the following:
//
// - Azure Blob storage resource.
// - Azure Queue storage resource.
// - Azure Table storage resource.
// After adding all resources, run the app...
Lorsque vous ajoutez un AzureStorageResource
à l’hôte de l’application, il expose d’autres API utiles pour ajouter Azure ressources de stockage Blob, File d’attente et Table. En d’autres termes, vous devez ajouter une AzureStorageResource
avant d’ajouter l’une des autres ressources de stockage.
Important
Lorsque vous appelez AddAzureStorage, il appelle implicitement AddAzureProvisioning, ce qui ajoute la prise en charge de la génération dynamique de ressources Azure pendant le démarrage de l’application. L’application doit configurer l’abonnement et l’emplacement appropriés. Pour plus d'informations, consultez Provisionnement Local : Configuration.
Génération de scripts Bicep pour l'approvisionnement
Si vous êtes nouveau dans Bicep, c'est un langage spécifique au domaine pour définir des ressources Azure. Avec .NET.NET Aspire, vous n’avez pas besoin d’écrire Bicep manuellement, au lieu de cela, les API d’approvisionnement génèrent Bicep pour vous. Lorsque vous publiez votre application, le Bicep généré est fourni avec le fichier manifeste. Lorsque vous ajoutez une ressource de stockage Azure, le Bicep suivant est généré :
bascule Azure Stockage Bicep.
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location
param principalId string
param principalType string
resource storage 'Microsoft.Storage/storageAccounts@2024-01-01' = {
name: take('storage${uniqueString(resourceGroup().id)}', 24)
kind: 'StorageV2'
location: location
sku: {
name: 'Standard_GRS'
}
properties: {
accessTier: 'Hot'
allowSharedKeyAccess: false
minimumTlsVersion: 'TLS1_2'
networkAcls: {
defaultAction: 'Allow'
}
}
tags: {
'aspire-resource-name': 'storage'
}
}
resource blobs 'Microsoft.Storage/storageAccounts/blobServices@2024-01-01' = {
name: 'default'
parent: storage
}
resource storage_StorageBlobDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storage.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'))
properties: {
principalId: principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')
principalType: principalType
}
scope: storage
}
resource storage_StorageTableDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storage.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3'))
properties: {
principalId: principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')
principalType: principalType
}
scope: storage
}
resource storage_StorageQueueDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storage.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88'))
properties: {
principalId: principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88')
principalType: principalType
}
scope: storage
}
output blobEndpoint string = storage.properties.primaryEndpoints.blob
output queueEndpoint string = storage.properties.primaryEndpoints.queue
output tableEndpoint string = storage.properties.primaryEndpoints.table
Bicep précédent est un module qui provisionne un compte de stockage Azure avec les valeurs par défaut suivantes :
-
kind
: type de compte de stockage. La valeur par défaut estStorageV2
. -
sku
: référence SKU du compte de stockage. La valeur par défaut estStandard_GRS
. -
properties
: propriétés du compte de stockage :-
accessTier
: niveau d’accès du compte de stockage. La valeur par défaut estHot
. -
allowSharedKeyAccess
: valeur booléenne qui indique si le compte de stockage autorise les demandes à être autorisées avec la clé d’accès du compte. La valeur par défaut estfalse
. -
minimumTlsVersion
: version TLS minimale prise en charge pour le compte de stockage. La valeur par défaut estTLS1_2
. -
networkAcls
: ACL réseau pour le compte de stockage. La valeur par défaut est{ defaultAction: 'Allow' }
.
-
En plus du compte de stockage, il provisionne également un conteneur blob.
Les attributions de rôles suivantes sont ajoutées au compte de stockage pour accorder à votre application l’accès. Pour plus d’informations, consultez les rôles intégrés Azure contrôle d’accès en fonction du rôle (Azure RBAC) :
Rôle / ID | Description |
---|---|
Contributeur de données Blob de stockageba92f5b4-2d11-453d-a403-e96b0029c9fe |
Lisez, écrivez et supprimez Azure conteneurs et objets blob de stockage. |
Contributeur aux données de table de stockage0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3 |
Lire, écrire et supprimer les tables de stockage et les entités Azure. |
Contributeur aux données de file d’attente de stockage974c5e8b-45b9-4653-ba55-5f855dd0fb88 |
Lisez, écrivez et supprimez Azure files d’attente et messages de file d’attente de stockage. |
Bicep généré est un point de départ et peut être personnalisé pour répondre à vos besoins spécifiques.
Personnaliser l’infrastructure d’approvisionnement
Toutes les ressources .NET AspireAzure sont des sous-classes du type AzureProvisioningResource. Ce type permet de personnaliser le Bicep généré en fournissant une API fluide pour configurer les ressources Azure à l'aide de l'API ConfigureInfrastructure<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure>). Par exemple, vous pouvez configurer le kind
, sku
, properties
, etc. L’exemple suivant montre comment personnaliser la ressource de stockage Azure :
builder.AddAzureStorage("storage")
.ConfigureInfrastructure(infra =>
{
var storageAccount = infra.GetProvisionableResources()
.OfType<StorageAccount>()
.Single();
storageAccount.AccessTier = StorageAccountAccessTier.Cool;
storageAccount.Sku = new StorageSku { Name = StorageSkuName.PremiumZrs };
storageAccount.Tags.Add("ExampleKey", "Example value");
});
Code précédent :
- Chaîne un appel à l’API ConfigureInfrastructure :
- Le paramètre
infra
est une instance du type AzureResourceInfrastructure. - Les ressources provisionnables sont récupérées en appelant la méthode GetProvisionableResources().
- La StorageAccount unique est récupérée.
- La StorageAccount.AccessTier est affectée à StorageAccountAccessTier.Cool.
- Le StorageAccount.Sku est affecté à un nouveau StorageSku avec une
Name
de PremiumZrs. - Une balise est ajoutée au compte de stockage avec une clé de
ExampleKey
et une valeur deExample value
.
- Le paramètre
Il existe de nombreuses autres options de configuration disponibles pour personnaliser la ressource de stockage Azure. Pour plus d’informations, consultez Azure.Provisioning.Storage.
Se connecter à un compte de stockage Azure existant
Vous disposez peut-être d’un compte de stockage Azure existant auquel vous souhaitez vous connecter. Au lieu de représenter une nouvelle ressource de stockage Azure, vous pouvez ajouter une chaîne de connexion à l’hôte de l’application. Pour ajouter une connexion à un compte de stockage Azure existant, appelez la méthode AddConnectionString :
var builder = DistributedApplication.CreateBuilder(args);
var blobs = builder.AddConnectionString("blobs");
builder.AddProject<Projects.WebApplication>("web")
.WithReference(blobs);
// After adding all resources, run the app...
Note
Les chaînes de connexion sont utilisées pour représenter un large éventail d’informations de connexion, notamment les connexions de base de données, les répartiteurs de messages, les URI de point de terminaison et d’autres services. Dans .NET.NET Aspire nomenclature, le terme « chaîne de connexion » est utilisé pour représenter n’importe quel type d’informations de connexion.
La chaîne de connexion est configurée dans la configuration de l’hôte d’application, généralement sous secrets utilisateur, sous la section ConnectionStrings
. L’hôte de l’application injecte cette chaîne de connexion en tant que variable d’environnement dans toutes les ressources dépendantes, par exemple :
{
"ConnectionStrings": {
"blobs": "https://{account_name}.blob.core.windows.net/"
}
}
La ressource dépendante peut accéder à la chaîne de connexion injectée en appelant la méthode GetConnectionString et en passant le nom de connexion en tant que paramètre, dans ce cas "blobs"
. L’API GetConnectionString
est abrégée pour IConfiguration.GetSection("ConnectionStrings")[name]
.
Ajouter la ressource d’émulateur de stockage Azure
Pour ajouter une ressource d’émulateur de stockage Azure, chaînez un appel sur un IResourceBuilder<AzureStorageResource>
à l’API RunAsEmulator :
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage")
.RunAsEmulator();
// After adding all resources, run the app...
Lorsque vous appelez RunAsEmulator
, il configure vos ressources de stockage pour qu’elles s’exécutent localement à l’aide d’un émulateur. L’émulateur dans ce cas est Azurite. L’émulateur open source Azurite fournit un environnement local gratuit pour tester vos applications Blob, File d’attente et Stockage Table Azure, et c’est un compagnon idéal pour l’intégration de l’hébergement .NET AspireAzure. Azurite n’est pas installé, au lieu de cela, il est accessible à .NET.NET Aspire en tant que conteneur. Lorsque vous ajoutez un conteneur à l’hôte d’application, comme illustré dans l’exemple précédent avec l’image mcr.microsoft.com/azure-storage/azurite
, il crée et démarre le conteneur au démarrage de l’hôte de l’application. Pour plus d’informations, consultez cycle de vie des ressources conteneur.
Configurer le conteneur Azurite
Il existe différentes configurations disponibles pour les ressources de conteneur, par exemple, vous pouvez configurer les ports du conteneur, les variables d’environnement, sa durée de vie, et plus.
Configurer les ports de conteneur Azurite
Par défaut, le conteneur Azurite lorsqu’il est configuré par .NET.NET Aspireexpose les points de terminaison suivants :
Point de terminaison | Port de conteneur | Port hôte |
---|---|---|
blob |
10 000 | dynamique |
queue |
10001 | dynamique |
table |
10002 | dynamique |
Le port sur lequel ils écoutent est dynamique par défaut. Au démarrage du conteneur, les ports sont mappés à un port aléatoire sur l’ordinateur hôte. Pour configurer les ports de l'endpoint, utilisez des appels chaînés sur le constructeur de ressources de conteneur fourni par la méthode RunAsEmulator
, comme indiqué dans l'exemple suivant :
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage").RunAsEmulator(
azurite =>
{
azurite.WithBlobPort("blob", 27000)
.WithQueuePort("queue", 27001)
.WithTablePort("table", 27002);
});
// After adding all resources, run the app...
Le code précédent configure les points de terminaison blob
, queue
et table
existants du conteneur Azurite pour écouter sur les ports 27000
, 27001
et 27002
, respectivement. Les ports du conteneur Azurite sont mappés aux ports hôtes, comme indiqué dans le tableau suivant :
Nom du point de terminaison | Mappage de ports (container:host ) |
---|---|
blob |
10000:27000 |
queue |
10001:27001 |
table |
10002:27002 |
Configurer un conteneur Azurite avec une durée de vie persistante
Pour configurer le conteneur Azurite avec une durée de vie persistante, appelez la méthode WithLifetime sur la ressource de conteneur Azurite et transmettez ContainerLifetime.Persistent:
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage").RunAsEmulator(
azurite =>
{
azurite.WithLifetime(ContainerLifetime.Persistent);
});
// After adding all resources, run the app...
Pour plus d'informations, consultez la durée de vie des ressources du conteneur.
Configurer un conteneur Azurite avec un volume de données
Pour ajouter un volume de données à la ressource de l’émulateur de stockage Azure, appelez la méthode WithDataVolume sur la ressource de l’émulateur de stockage Azure :
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage").RunAsEmulator(
azurite =>
{
azurite.WithDataVolume();
});
// After adding all resources, run the app...
Le volume de données est utilisé pour conserver les données Azurite en dehors du cycle de vie de son conteneur. Le volume de données est monté sur le chemin /data
dans le conteneur Azurite et lorsqu’un paramètre name
n’est pas fourni, le nom est formaté comme .azurite/{resource name}
. Pour plus d’informations sur les volumes de données et pourquoi ils sont préférés par rapport aux montages de liaison , consultez la documentation de Docker : Volumes.
Configurer un conteneur Azurite avec montage de liaison de données
Pour ajouter un montage de liaison de données à la ressource de l’émulateur de stockage Azure, appelez la méthode WithDataBindMount :
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage").RunAsEmulator(
azurite =>
{
azurite.WithDataBindMount("../Azurite/Data");
});
// After adding all resources, run the app...
Important
Les montages de liaison de données ont des fonctionnalités limitées par rapport aux volumes , qui offrent de meilleures performances, une meilleure portabilité et sécurité, les rendant ainsi plus adaptés aux environnements de production. Toutefois, les montages de liaison autorisent l’accès direct et la modification des fichiers sur le système hôte, ce qui est idéal pour le développement et le test nécessitant des modifications en temps réel.
Les montages de liaison de données s’appuient sur le système de fichiers de l’ordinateur hôte pour conserver les données Azurite entre les redémarrages de conteneur. Le point de montage de liaison de données est monté au chemin d’accès ../Azurite/Data
sur l’ordinateur hôte par rapport au répertoire hôte de l’application (IDistributedApplicationBuilder.AppHostDirectory) dans le conteneur Azurite. Pour plus d'informations sur les montages de liaison de données, consultez Docker docs : Montages de liaison.
Se connecter aux ressources de stockage
Lorsque l’hôte d’application .NET.NET Aspire s’exécute, les ressources de stockage sont accessibles par des outils externes, tels que l’Explorateur stockage Azure. Si votre ressource de stockage s’exécute localement à l’aide d’Azurite, elle est automatiquement récupérée par l’Explorateur stockage Azure.
Note
L’Explorateur stockage Azure découvre les ressources de stockage Azurite en supposant que les ports par défaut sont utilisés. Si vous avez configuré le conteneur Azurite pour utiliser différents ports, vous devez configurer l’Explorateur de stockage Azure pour vous connecter aux ports appropriés.
Pour vous connecter à la ressource de stockage à partir de Azure Explorateur Stockage, procédez comme suit :
Exécutez l’hôte d’application .NET.NET Aspire.
Ouvrez l’Explorateur stockage Azure.
Affichez le volet de l’Explorateur
. Sélectionnez le lien Actualiser tous pour actualiser la liste des comptes de stockage.
Développez le nœud attaché à l’émulateur &.
Développez le nœud comptes de stockage.
Vous devez voir un compte de stockage portant le nom de votre ressource comme préfixe :
Vous êtes libre d’explorer le compte de stockage et son contenu à l’aide de l’Explorateur stockage Azure. Pour plus d’informations sur l’utilisation de l’Explorateur stockage Azure, consultez Prise en main de l’Explorateur Stockage.
Ajouter la ressource de stockage de file d'attente Azure
Dans votre projet hôte d’application, enregistrez l’intégration du stockage de file d'attente Azure en chaînant un appel à AddQueues sur l’instance de IResourceBuilder<IAzureStorageResource>
retournée par AddAzureStorage. L’exemple suivant montre comment ajouter une ressource de stockage file d’attente Azure nommée storage
et une ressource de file d’attente nommée queues
:
var builder = DistributedApplication.CreateBuilder(args);
var queues = builder.AddAzureStorage("storage")
.AddQueues("queues");
builder.AddProject<Projects.ExampleProject>()
.WithReference(queues);
// After adding all resources, run the app...
Code précédent :
- Ajoute une ressource de stockage Azure nommée
storage
. - Ajoute une file d’attente nommée
queues
à la ressource de stockage. - Ajoute la ressource
storage
auExampleProject
et attend qu’elle soit prête avant de démarrer le projet.
Vérifications d’intégrité de l’intégration d’hébergement
L’intégration de l’hébergement de stockage Azure ajoute automatiquement un contrôle d’intégrité pour la ressource de stockage. Elle est ajoutée uniquement lors de l’exécution en tant qu’émulateur et vérifie que le conteneur Azurite est en cours d’exécution et qu’une connexion peut être établie à celui-ci. L’intégration de l’hébergement s’appuie sur les 📦 AspNetCore.HealthChecks.Azure.Storage.Blobs paquet NuGet.
intégration de Client
Pour commencer à utiliser l'intégration du stockage de file d'attente .NET AspireAzureclient, installez le package NuGet 📦Aspire.Azure.Storage.Queues dans le projet consommant client, c'est-à-dire le projet pour l'application qui utilise le stockage de file d'attente Azureclient. L’intégration Azure Stockage File d’attente client inscrit une instance de QueueServiceClient que vous pouvez utiliser pour interagir avec Azure Stockage File d’attente.
dotnet add package Aspire.Azure.Storage.Queues
Ajouter Azure Stockage en file d'attente client
Dans le fichier Program.cs de votre projet consommant client, appelez la méthode d’extension AddAzureQueueClient sur n’importe quel IHostApplicationBuilder pour inscrire un QueueServiceClient
afin de pouvoir l'utiliser via le conteneur d’injection de dépendance. La méthode prend un paramètre de nom de connexion.
builder.AddAzureQueueClient("queue");
Vous pouvez ensuite récupérer l’instance QueueServiceClient
à l’aide de l’injection de dépendances. Par exemple, pour récupérer le client à partir d’un service :
public class ExampleService(QueueServiceClient client)
{
// Use client...
}
Configuration
L’intégration de stockage file d’attente .NET AspireAzure fournit plusieurs options pour configurer l'QueueServiceClient
en fonction des exigences et des conventions de votre projet.
Utiliser une chaîne de connexion
Lorsque vous utilisez une chaîne de connexion à partir de la section de configuration ConnectionStrings
, vous pouvez fournir le nom de la chaîne de connexion lors de l’appel de AddAzureQueueClient:
builder.AddAzureQueueClient("queue");
Ensuite, la chaîne de connexion est récupérée à partir de la section de configuration ConnectionStrings
, et deux formats de connexion sont pris en charge :
URI de service
L’approche recommandée consiste à utiliser un ServiceUri
, qui fonctionne avec la propriété AzureStorageQueuesSettings.Credential pour établir une connexion. Si aucune information d’identification n’est configurée, la Azure.Identity.DefaultAzureCredential est utilisée.
{
"ConnectionStrings": {
"queue": "https://{account_name}.queue.core.windows.net/"
}
}
Chaîne de connexion
Vous pouvez également utiliser une chaîne de connexion de stockage Azure.
{
"ConnectionStrings": {
"queue": "AccountName=myaccount;AccountKey=myaccountkey"
}
}
Pour plus d’informations, consultez Configurer des chaînes de connexion de stockage Azure.
Utiliser des fournisseurs de configuration
L'intégration de la file d'attente de stockage .NET AspireAzure prend en charge Microsoft.Extensions.Configuration. Il charge les AzureStorageQueuesSettings et les QueueClientOptions à partir de la configuration à l’aide de la clé Aspire:Azure:Storage:Queues
. L’extrait de code suivant est un exemple de fichier appsettings.json qui configure certaines des options :
{
"Aspire": {
"Azure": {
"Storage": {
"Queues": {
"DisableHealthChecks": true,
"DisableTracing": false,
"ClientOptions": {
"Diagnostics": {
"ApplicationId": "myapp"
}
}
}
}
}
}
}
Pour obtenir le schéma complet Azure Storage Queuesclient d’intégration JSON, consultez Aspire.Azure. Data.Queues/ConfigurationSchema.json.
Utiliser des délégués en ligne
Vous pouvez également transmettre le délégué Action<AzureStorageQueuesSettings> configureSettings
pour configurer certaines ou toutes les options directement, par exemple pour paramétrer les vérifications d'intégrité :
builder.AddAzureQueueClient(
"queue",
settings => settings.DisableHealthChecks = true);
Vous pouvez également configurer le QueueClientOptions en utilisant le délégué Action<IAzureClientBuilder<QueueServiceClient, QueueClientOptions>> configureClientBuilder
, le deuxième paramètre de la méthode AddAzureQueueClient
. Par exemple, pour définir la première partie des en-têtes de l'user-agent pour toutes les requêtes émises par ce client:
builder.AddAzureQueueClient(
"queue",
configureClientBuilder: clientBuilder =>
clientBuilder.ConfigureOptions(
options => options.Diagnostics.ApplicationId = "myapp"));
Client tests de santé de l'intégration
Les intégrations .NET.NET Aspire activent les vérifications de santé pour tous les services, par défaut. Pour plus d’informations, consultez .NET.NET Aspire vue d’ensemble des intégrations.
L'intégration du stockage des files d’attente .NET AspireAzure :
- Ajoute la vérification d’intégrité lorsque AzureStorageQueuesSettings.DisableHealthChecks est
false
et tente de se connecter au stockage de files d'attente Azure. - S’intègre au point de terminaison HTTP
/health
, qui spécifie que tous les contrôles de santé inscrits doivent être réussis pour que l'application soit considérée prête à accepter le trafic.
Observabilité et télémétrie
.NET .NET Aspire intégrations configurent automatiquement les configurations de journalisation, de suivi et de métriques, parfois appelées les piliers de l’observabilité. Pour plus d’informations sur l’observabilité de l’intégration et la télémétrie, consultez .NET.NET Aspire vue d’ensemble des intégrations. Selon le service de stockage, certaines intégrations peuvent uniquement prendre en charge certaines de ces fonctionnalités. Par exemple, certaines intégrations prennent en charge la journalisation et le suivi, mais pas les métriques. Les fonctionnalités de télémétrie peuvent également être désactivées à l’aide des techniques présentées dans la section Configuration.
Exploitation forestière
L'intégration de stockage de file d'attente .NET AspireAzure utilise les catégories de journaux suivantes :
Azure.Core
Azure.Identity
Traçage
L’intégration du stockage de la file d’attente .NET AspireAzure émet les activités de suivi suivantes à l’aide de OpenTelemetry:
Azure.Storage.Queues.QueueClient
Métriques
L’intégration de stockage file d’attente .NET AspireAzure ne prend actuellement pas en charge les métriques par défaut en raison de limitations avec le SDK Azure.
Voir aussi
- Documentation du stockage des files d'attente Azure
- intégrations .NET.NET Aspire
- .NET Aspire GitHub référentiel