Créer des intégrations de .NET Aspireclient personnalisées
Cet article est une continuation de l’article Créer des intégrations d’hébergement personnalisées .NET.NET Aspire. Il vous guide tout au long de la création d’une intégration .NET Aspireclient qui utilise MailKit pour envoyer des e-mails. Cette intégration est ensuite ajoutée à l’application Bulletin d’informations que vous avez créée précédemment. L’exemple précédent a omis la création d’une intégration client et s’appuyait plutôt sur le .NETSmtpClient
existant. Il est préférable d’utiliser les SmtpClient
de MailKit plutôt que les .NETSmtpClient
officiels pour l’envoi d’e-mails, car il est plus moderne et prend en charge davantage de fonctionnalités et de protocoles. Pour plus d’informations, consultez .NET SmtpClient : Remarques.
Conditions préalables
Si vous avez suivi le processus, vous devriez avoir une application de newsletter à partir des étapes décrites dans l'article Créer une .NET.NET Aspire d’intégration d’hébergement personnalisé.
Pourboire
Cet article est inspiré par des intégrations .NET.NET Aspire existantes et basées sur les conseils officiels de l’équipe. Il y a des endroits où les conseils varient, et il est important de comprendre le raisonnement derrière les différences. Pour plus d’informations, consultez .NET.NET Aspire exigences d’intégration.
Créer une bibliothèque pour l’intégration
.NET .NET Aspire intégrations sont fournies comme packages NuGet, mais dans cet exemple, cela dépasse le cadre de cet article de publier un package NuGet. Au lieu de cela, vous créez un projet de bibliothèque de classes qui contient l’intégration et le référencez en tant que projet. Les packages d’intégration .NET Aspire sont destinés à encapsuler une bibliothèque comme client, telle que MailKit, et à fournir une télémétrie prête pour la production, des contrôles d’intégrité, ainsi qu’une configurabilité et une testabilité. Commençons par créer un projet de bibliothèque de classes.
Créez un projet de bibliothèque de classes nommé
MailKit.Client
dans le même répertoire que le MailDevResource.sln de l’article précédent.dotnet new classlib -o MailKit.Client
Ajoutez le projet à la solution.
dotnet sln ./MailDevResource.sln add MailKit.Client/MailKit.Client.csproj
L’étape suivante consiste à ajouter tous les packages NuGet sur lesquels l’intégration s’appuie. Au lieu d’ajouter chaque package un par un à partir de l’interface CLI .NET, il est probablement plus facile de copier et coller le code XML suivant dans le fichier .csproj de MailKit Client.
<ItemGroup>
<PackageReference Include="MailKit" Version="4.9.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Resilience" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.0" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
</ItemGroup>
Définir les paramètres d’intégration
Chaque fois que vous créez une intégration .NET Aspire, il est préférable de comprendre la bibliothèque client à laquelle vous effectuez un mappage. Avec MailKit, vous devez comprendre les paramètres de configuration requis pour vous connecter à un protocole SMTP (Simple Mail Transfer Protocol) server. Mais il est également important de comprendre si la bibliothèque prend en charge contrôles de santé, le suivi , et des métriques . MailKit prend en charge MailKit.Client
dans un fichier nommé MailKitClientSettings.cs:
using System.Data.Common;
namespace MailKit.Client;
/// <summary>
/// Provides the client configuration settings for connecting MailKit to an SMTP server.
/// </summary>
public sealed class MailKitClientSettings
{
internal const string DefaultConfigSectionName = "MailKit:Client";
/// <summary>
/// Gets or sets the SMTP server <see cref="Uri"/>.
/// </summary>
/// <value>
/// The default value is <see langword="null"/>.
/// </value>
public Uri? Endpoint { get; set; }
/// <summary>
/// Gets or sets a boolean value that indicates whether the database health check is disabled or not.
/// </summary>
/// <value>
/// The default value is <see langword="false"/>.
/// </value>
public bool DisableHealthChecks { get; set; }
/// <summary>
/// Gets or sets a boolean value that indicates whether the OpenTelemetry tracing is disabled or not.
/// </summary>
/// <value>
/// The default value is <see langword="false"/>.
/// </value>
public bool DisableTracing { get; set; }
/// <summary>
/// Gets or sets a boolean value that indicates whether the OpenTelemetry metrics are disabled or not.
/// </summary>
/// <value>
/// The default value is <see langword="false"/>.
/// </value>
public bool DisableMetrics { get; set; }
internal void ParseConnectionString(string? connectionString)
{
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new InvalidOperationException($"""
ConnectionString is missing.
It should be provided in 'ConnectionStrings:<connectionName>'
or '{DefaultConfigSectionName}:Endpoint' key.'
configuration section.
""");
}
if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))
{
Endpoint = uri;
}
else
{
var builder = new DbConnectionStringBuilder
{
ConnectionString = connectionString
};
if (builder.TryGetValue("Endpoint", out var endpoint) is false)
{
throw new InvalidOperationException($"""
The 'ConnectionStrings:<connectionName>' (or 'Endpoint' key in
'{DefaultConfigSectionName}') is missing.
""");
}
if (Uri.TryCreate(endpoint.ToString(), UriKind.Absolute, out uri) is false)
{
throw new InvalidOperationException($"""
The 'ConnectionStrings:<connectionName>' (or 'Endpoint' key in
'{DefaultConfigSectionName}') isn't a valid URI.
""");
}
Endpoint = uri;
}
}
}
Le code précédent définit la classe MailKitClientSettings
avec :
-
Endpoint
propriété qui représente la chaîne de connexion au serverSMTP . -
DisableHealthChecks
propriété qui détermine si les vérifications de l'état de santé sont activées. -
DisableTracing
propriété qui détermine si le suivi est activé. -
DisableMetrics
propriété qui détermine si les métriques sont activées.
Analyser la logique de chaîne de connexion
La classe settings contient également une méthode ParseConnectionString
qui analyse la chaîne de connexion en un Uri
valide. La configuration doit être fournie au format suivant :
-
ConnectionStrings:<connectionName>
: la chaîne de connexion au serveur serverSMTP. -
MailKit:Client:ConnectionString
: La chaîne de connexion pour le serverSMTP.
Si aucune de ces valeurs n’est fournie, une exception est levée.
Exposer la fonctionnalité client
L’objectif des intégrations .NET Aspire est d’exposer la bibliothèque sous-jacente client aux utilisateurs par injection de dépendance. Avec MailKit et pour cet exemple, la classe SmtpClient
est ce que vous souhaitez exposer. Vous n’encapsulez aucune fonctionnalité, mais plutôt mappez les paramètres de configuration à une classe SmtpClient
. Il est courant d'exposer les enregistrements standard et les services à clé pour les intégrations. Les inscriptions standard sont utilisées lorsqu’il n’existe qu’une seule instance d’un service et que les inscriptions de service à clé sont utilisées lorsqu’il existe plusieurs instances d’un service. Parfois, pour obtenir plusieurs inscriptions du même type, vous utilisez un modèle de fabrique. Ajoutez le code suivant au projet MailKit.Client
dans un fichier nommé MailKitClientFactory.cs:
using MailKit.Net.Smtp;
namespace MailKit.Client;
/// <summary>
/// A factory for creating <see cref="ISmtpClient"/> instances
/// given a <paramref name="smtpUri"/> (and optional <paramref name="credentials"/>).
/// </summary>
/// <param name="settings">
/// The <see cref="MailKitClientSettings"/> settings for the SMTP server
/// </param>
public sealed class MailKitClientFactory(MailKitClientSettings settings) : IDisposable
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
private SmtpClient? _client;
/// <summary>
/// Gets an <see cref="ISmtpClient"/> instance in the connected state
/// (and that's been authenticated if configured).
/// </summary>
/// <param name="cancellationToken">Used to abort client creation and connection.</param>
/// <returns>A connected (and authenticated) <see cref="ISmtpClient"/> instance.</returns>
/// <remarks>
/// Since both the connection and authentication are considered expensive operations,
/// the <see cref="ISmtpClient"/> returned is intended to be used for the duration of a request
/// (registered as 'Scoped') and is automatically disposed of.
/// </remarks>
public async Task<ISmtpClient> GetSmtpClientAsync(
CancellationToken cancellationToken = default)
{
await _semaphore.WaitAsync(cancellationToken);
try
{
if (_client is null)
{
_client = new SmtpClient();
await _client.ConnectAsync(settings.Endpoint, cancellationToken)
.ConfigureAwait(false);
}
}
finally
{
_semaphore.Release();
}
return _client;
}
public void Dispose()
{
_client?.Dispose();
_semaphore.Dispose();
}
}
La classe MailKitClientFactory
est une fabrique qui crée une instance ISmtpClient
en fonction des paramètres de configuration. Il est chargé de retourner une implémentation de ISmtpClient
qui a une connexion active à un SMTP serverconfiguré. Ensuite, vous devez exposer la fonctionnalité aux consommateurs pour enregistrer cette fabrique auprès du conteneur d’injection de dépendances. Ajoutez le code suivant au projet MailKit.Client
dans un fichier nommé MailKitExtensions.cs:
using MailKit;
using MailKit.Client;
using MailKit.Net.Smtp;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Extensions.Hosting;
/// <summary>
/// Provides extension methods for registering a <see cref="SmtpClient"/> as a
/// scoped-lifetime service in the services provided by the <see cref="IHostApplicationBuilder"/>.
/// </summary>
public static class MailKitExtensions
{
/// <summary>
/// Registers 'Scoped' <see cref="MailKitClientFactory" /> for creating
/// connected <see cref="SmtpClient"/> instance for sending emails.
/// </summary>
/// <param name="builder">
/// The <see cref="IHostApplicationBuilder" /> to read config from and add services to.
/// </param>
/// <param name="connectionName">
/// A name used to retrieve the connection string from the ConnectionStrings configuration section.
/// </param>
/// <param name="configureSettings">
/// An optional delegate that can be used for customizing options.
/// It's invoked after the settings are read from the configuration.
/// </param>
public static void AddMailKitClient(
this IHostApplicationBuilder builder,
string connectionName,
Action<MailKitClientSettings>? configureSettings = null) =>
AddMailKitClient(
builder,
MailKitClientSettings.DefaultConfigSectionName,
configureSettings,
connectionName,
serviceKey: null);
/// <summary>
/// Registers 'Scoped' <see cref="MailKitClientFactory" /> for creating
/// connected <see cref="SmtpClient"/> instance for sending emails.
/// </summary>
/// <param name="builder">
/// The <see cref="IHostApplicationBuilder" /> to read config from and add services to.
/// </param>
/// <param name="name">
/// The name of the component, which is used as the <see cref="ServiceDescriptor.ServiceKey"/> of the
/// service and also to retrieve the connection string from the ConnectionStrings configuration section.
/// </param>
/// <param name="configureSettings">
/// An optional method that can be used for customizing options. It's invoked after the settings are
/// read from the configuration.
/// </param>
public static void AddKeyedMailKitClient(
this IHostApplicationBuilder builder,
string name,
Action<MailKitClientSettings>? configureSettings = null)
{
ArgumentNullException.ThrowIfNull(name);
AddMailKitClient(
builder,
$"{MailKitClientSettings.DefaultConfigSectionName}:{name}",
configureSettings,
connectionName: name,
serviceKey: name);
}
private static void AddMailKitClient(
this IHostApplicationBuilder builder,
string configurationSectionName,
Action<MailKitClientSettings>? configureSettings,
string connectionName,
object? serviceKey)
{
ArgumentNullException.ThrowIfNull(builder);
var settings = new MailKitClientSettings();
builder.Configuration
.GetSection(configurationSectionName)
.Bind(settings);
if (builder.Configuration.GetConnectionString(connectionName) is string connectionString)
{
settings.ParseConnectionString(connectionString);
}
configureSettings?.Invoke(settings);
if (serviceKey is null)
{
builder.Services.AddScoped(CreateMailKitClientFactory);
}
else
{
builder.Services.AddKeyedScoped(serviceKey, (sp, key) => CreateMailKitClientFactory(sp));
}
MailKitClientFactory CreateMailKitClientFactory(IServiceProvider _)
{
return new MailKitClientFactory(settings);
}
if (settings.DisableHealthChecks is false)
{
builder.Services.AddHealthChecks()
.AddCheck<MailKitHealthCheck>(
name: serviceKey is null ? "MailKit" : $"MailKit_{connectionName}",
failureStatus: default,
tags: []);
}
if (settings.DisableTracing is false)
{
builder.Services.AddOpenTelemetry()
.WithTracing(
traceBuilder => traceBuilder.AddSource(
Telemetry.SmtpClient.ActivitySourceName));
}
if (settings.DisableMetrics is false)
{
// Required by MailKit to enable metrics
Telemetry.SmtpClient.Configure();
builder.Services.AddOpenTelemetry()
.WithMetrics(
metricsBuilder => metricsBuilder.AddMeter(
Telemetry.SmtpClient.MeterName));
}
}
}
Le code précédent ajoute deux méthodes d’extension sur le type IHostApplicationBuilder
, une pour l’inscription standard de MailKit et une autre pour l’inscription à clé de MailKit.
Pourboire
Les méthodes d’extension pour les intégrations .NET.NET Aspire doivent étendre le type IHostApplicationBuilder
et suivre la convention d’affectation de noms Add<MeaningfulName>
où le <MeaningfulName>
est le type ou la fonctionnalité que vous ajoutez. Pour cet article, la méthode d’extension AddMailKitClient
est utilisée pour ajouter le clientMailKit . Il est probablement plus conforme aux conseils officiels d’utiliser AddMailKitSmtpClient
au lieu de AddMailKitClient
, car cela inscrit uniquement le SmtpClient
et non l’ensemble de la bibliothèque MailKit.
Les deux extensions s’appuient finalement sur la méthode privée AddMailKitClient
pour inscrire le MailKitClientFactory
auprès du conteneur d’injection de dépendances en tant que service à portée . La raison de l’inscription de l'MailKitClientFactory
en tant que service étendu est que les opérations de connexion sont considérées comme coûteuses et doivent être réutilisées dans la même étendue dans la mesure du possible. En d’autres termes, pour une requête unique, la même instance de ISmtpClient
doit être utilisée. La fabrique conserve l’instance du SmtpClient
qu’elle crée et s’en débarrasse.
Liaison de configuration
L’une des premières choses que fait l’implémentation privée des méthodes AddMailKitClient
consiste à lier les paramètres de configuration à la classe MailKitClientSettings
. La classe de paramètres est instanciée, puis Bind
est appelée avec la section spécifique de la configuration. Ensuite, le délégué configureSettings
facultatif est appelé avec les paramètres actuels. Cela permet au consommateur de configurer davantage les paramètres, en veillant à ce que les paramètres de code manuel soient respectés sur les paramètres de configuration. Après cela, selon que la valeur de serviceKey
a été fournie, MailKitClientFactory
doit être enregistrée dans le conteneur d'injection de dépendances en tant que service standard ou service avec clé.
Important
Il est intentionnel que la surcharge implementationFactory
soit appelée lors de l’inscription des services. La méthode CreateMailKitClientFactory
lève une exception lorsque la configuration n’est pas valide. Cela garantit que la création de l'MailKitClientFactory
est différée jusqu’à ce qu’elle soit nécessaire et empêche l’application d’effectuer des erreurs avant que la journalisation soit disponible.
L’enregistrement des vérifications de santé et la télémétrie est décrit plus en détail dans les sections suivantes.
Ajouter des vérifications d’intégrité
Les vérifications d’intégrité sont un moyen pour surveiller l’intégrité d’une intégration. Avec MailKit, vous pouvez vérifier si la connexion au server SMTP est saine. Ajoutez le code suivant au projet MailKit.Client
dans un fichier nommé MailKitHealthCheck.cs:
using Microsoft.Extensions.Diagnostics.HealthChecks;
namespace MailKit.Client;
internal sealed class MailKitHealthCheck(MailKitClientFactory factory) : IHealthCheck
{
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
// The factory connects (and authenticates).
_ = await factory.GetSmtpClientAsync(cancellationToken);
return HealthCheckResult.Healthy();
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy(exception: ex);
}
}
}
Implémentation précédente de la vérification de l'état de santé :
- Implémente l’interface
IHealthCheck
. - Accepte le
MailKitClientFactory
comme paramètre de constructeur principal. - Satisfait la méthode
CheckHealthAsync
par :- Tentative de récupérer une instance de
ISmtpClient
à partir dufactory
. Si elle réussit, elle retourneHealthCheckResult.Healthy
. - Si une exception est levée, elle retourne
HealthCheckResult.Unhealthy
.
- Tentative de récupérer une instance de
Comme mentionné précédemment lors de l'enregistrement du MailKitClientFactory
, le MailKitHealthCheck
est conditionnellement enregistré auprès de l'IHeathChecksBuilder
:
if (settings.DisableHealthChecks is false)
{
builder.Services.AddHealthChecks()
.AddCheck<MailKitHealthCheck>(
name: serviceKey is null ? "MailKit" : $"MailKit_{connectionName}",
failureStatus: default,
tags: []);
}
Le consommateur peut choisir d’omettre les contrôles de santé en réglant la propriété DisableHealthChecks
sur true
dans la configuration. Un modèle courant pour les intégrations consiste à avoir des fonctionnalités facultatives et .NET.NET Aspire intégrations encourage fortement ces types de configurations. Pour plus d'informations sur les vérifications d'intégrité et un exemple fonctionnel qui inclut une interface utilisateur, consultez l'exemple HealthChecksUI .NET AspireASP.NET Core.
Configurer la télémétrie
Comme meilleure pratique, la bibliothèque MailKit client expose les données de télémétrie. .NET .NET Aspire pouvez tirer parti de cette télémétrie et l’afficher dans le tableau de bord .NET.NET Aspire. Selon que le suivi et les métriques sont activés ou non, les données de télémétrie sont câblées comme indiqué dans l’extrait de code suivant :
if (settings.DisableTracing is false)
{
builder.Services.AddOpenTelemetry()
.WithTracing(
traceBuilder => traceBuilder.AddSource(
Telemetry.SmtpClient.ActivitySourceName));
}
if (settings.DisableMetrics is false)
{
// Required by MailKit to enable metrics
Telemetry.SmtpClient.Configure();
builder.Services.AddOpenTelemetry()
.WithMetrics(
metricsBuilder => metricsBuilder.AddMeter(
Telemetry.SmtpClient.MeterName));
}
Mettre à jour le service Bulletin d’informations
Une fois la bibliothèque d’intégration créée, vous pouvez maintenant mettre à jour le service Bulletin d’informations pour utiliser l'clientMailKit. La première étape consiste à ajouter une référence au projet MailKit.Client
. Ajoutez la référence MailKit.Client.csproj au projet MailDevResource.NewsletterService
:
dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference MailKit.Client/MailKit.Client.csproj
Ensuite, ajoutez une référence au projet ServiceDefaults
:
dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference MailDevResource.ServiceDefaults/MailDevResource.ServiceDefaults.csproj
La dernière étape consiste à remplacer le fichier Program.cs existant dans le projet MailDevResource.NewsletterService
par le code C# suivant :
using System.Net.Mail;
using MailKit.Client;
using MailKit.Net.Smtp;
using MimeKit;
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Add services to the container.
builder.AddMailKitClient("maildev");
var app = builder.Build();
app.MapDefaultEndpoints();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.MapPost("/subscribe",
async (MailKitClientFactory factory, string email) =>
{
ISmtpClient client = await factory.GetSmtpClientAsync();
using var message = new MailMessage("newsletter@yourcompany.com", email)
{
Subject = "Welcome to our newsletter!",
Body = "Thank you for subscribing to our newsletter!"
};
await client.SendAsync(MimeMessage.CreateFromMailMessage(message));
});
app.MapPost("/unsubscribe",
async (MailKitClientFactory factory, string email) =>
{
ISmtpClient client = await factory.GetSmtpClientAsync();
using var message = new MailMessage("newsletter@yourcompany.com", email)
{
Subject = "You are unsubscribed from our newsletter!",
Body = "Sorry to see you go. We hope you will come back soon!"
};
await client.SendAsync(MimeMessage.CreateFromMailMessage(message));
});
app.Run();
Les modifications les plus notables dans le code précédent sont les suivantes :
- Les déclarations
using
mises à jour qui incluent les espaces de nomsMailKit.Client
,MailKit.Net.Smtp
, etMimeKit
. - Remplacement de l'enregistrement pour le .NET
SmtpClient
officiel par l’appel à la méthode d’extensionAddMailKitClient
. - Le remplacement des appels de fonction de
/subscribe
et/unsubscribe
par l'injection deMailKitClientFactory
et l'utilisation de l'instance deISmtpClient
pour envoyer l'e-mail.
Exécuter l’exemple
Maintenant que vous avez créé l’intégration de MailKit client et mis à jour le service Bulletin d’informations pour l’utiliser, vous pouvez exécuter l’exemple. Dans votre IDE, sélectionnez F5 ou exécutez dotnet run
à partir du répertoire racine de la solution pour démarrer l’application. Vous devez voir le tableau de bord .NET.NET Aspire:
Une fois l’application en cours d’exécution, accédez à l’interface utilisateur Swagger à https://localhost:7251/swagger et testez les points de terminaison /subscribe
et /unsubscribe
. Sélectionnez la flèche vers le bas pour développer le point de terminaison :
Sélectionnez ensuite le bouton Try it out
. Entrez une adresse e-mail, puis sélectionnez le bouton Execute
.
Répétez cette opération plusieurs fois pour ajouter plusieurs adresses e-mail. Vous devez voir l’e-mail envoyé à la boîte de réception MailDev :
Arrêtez l’application en sélectionnant Ctrl+C dans la fenêtre de terminal où l’application est en cours d’exécution, ou en sélectionnant le bouton Arrêter dans votre IDE.
Afficher les données de télémétrie MailKit
La bibliothèque mailKit client expose les données de télémétrie qui peuvent être affichées dans le tableau de bord .NET Aspire. Pour afficher les données de télémétrie, accédez au tableau de bord .NET.NET Aspire à https://localhost:7251. Sélectionnez la ressource
Ouvrez à nouveau l’interface utilisateur Swagger et effectuez des requêtes aux points de terminaison /subscribe
et /unsubscribe
. Ensuite, revenez au tableau de bord .NET.NET Aspire et sélectionnez la ressource newsletter
. Sélectionnez une métrique sous le nœud mailkit.net.smtp, telle que mailkit.net.smtp.client.operation.count
. Vous devez voir les données de télémétrie pour l'clientMailKit :
Résumé
Dans cet article, vous avez appris à créer une intégration .NET.NET Aspire qui utilise MailKit pour envoyer des e-mails. Vous avez également appris à intégrer cette intégration dans l’application Bulletin d’informations que vous avez créée précédemment. Vous avez découvert les principes fondamentaux des intégrations de .NET Aspire, tels qu'exposer la bibliothèque de client sous-jacente aux consommateurs à travers l'injection de dépendances, et la façon d’ajouter des vérifications d'état et de la télémétrie à l’intégration. Vous avez également appris à mettre à jour le service Bulletin d’informations pour utiliser le clientMailKit.
Allez de l’avant et créez vos propres intégrations .NET.NET Aspire. Si vous pensez qu’il y a suffisamment de valeur de communauté dans l’intégration que vous créez, envisagez de le publier en tant que package NuGet pour que d’autres utilisateurs puissent l’utiliser. En outre, envisagez de soumettre une demande de fusion au référentiel .NET AspireGitHub afin qu'elle soit prise en considération pour inclusion dans les intégrations officielles .NET.NET Aspire.