Dela via


Skapa anpassade .NET Aspireclient-integreringar

Den här artikeln är en fortsättning på artikeln Skapa anpassade .NET.NET Aspire som är värd för integreringar. Den vägleder dig genom att skapa en .NET Aspireclient integrering som använder MailKit för att skicka e-postmeddelanden. Den här integreringen läggs sedan till i appen Nyhetsbrev som du skapade tidigare. I föregående exempel utelämnades skapandet av en client-integrering och förlitade sig i stället på den befintliga .NETSmtpClient. Det är bäst att använda MailKits SmtpClient över den officiella .NETSmtpClient för att skicka e-postmeddelanden, eftersom det är modernare och stöder fler funktioner/protokoll. Mer information finns i .NET SmtpClient: Kommentarer.

Förutsättningar

Om du följer instruktionerna bör du ha en nyhetsbrev-app från stegen i artikeln Skapa anpassad .NET.NET Aspire hosting-integration.

Tips

Den här artikeln är inspirerad av befintliga .NET.NET Aspire integreringar och baseras på teamets officiella vägledning. Det finns platser där den nämnda vägledningen varierar, och det är viktigt att förstå resonemanget bakom skillnaderna. Mer information finns i .NET.NET Aspire integrationskrav.

Skapa bibliotek för integrering

.NET .NET Aspire integreringar levereras som NuGet-paket, men i det här exemplet ligger det utanför omfånget för den här artikeln att publicera ett NuGet-paket. I stället skapar du ett klassbiblioteksprojekt som innehåller integreringen och refererar till det som ett projekt. .NET Aspire integreringspaket är avsedda att omsluta ett client-bibliotek, till exempel MailKit, och tillhandahålla produktionsklar telemetri, hälsokontroller, konfigurerbarhet och testbarhet. Vi börjar med att skapa ett nytt klassbiblioteksprojekt.

  1. Skapa ett nytt klassbiblioteksprojekt med namnet MailKit.Client i samma katalog som MailDevResource.sln från föregående artikel.

    dotnet new classlib -o MailKit.Client
    
  2. Lägg till projektet i lösningen.

    dotnet sln ./MailDevResource.sln add MailKit.Client/MailKit.Client.csproj
    

Nästa steg är att lägga till alla NuGet-paket som integreringen förlitar sig på. I stället för att lägga till varje paket en i taget från .NET CLI är det förmodligen enklare att kopiera och klistra in följande XML i MailKit.Client.csproj fil.

<ItemGroup>
  <PackageReference Include="MailKit" Version="4.9.0" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.1" />
  <PackageReference Include="Microsoft.Extensions.Resilience" Version="9.1.0" />
  <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.1" />
  <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="9.0.1" />
  <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" />
</ItemGroup>

Definiera integreringsinställningar

När du skapar en .NET Aspire integrering är det bäst att förstå det client bibliotek som du mappar till. Med MailKit måste du förstå de konfigurationsinställningar som krävs för att ansluta till ett SMTP-server(Simple Mail Transfer Protocol). Men det är också viktigt att förstå om biblioteket har stöd för hälsokontroller, spårning och mått. MailKit stöder spårning och metrik, genom sin Telemetry.SmtpClient klass. När du lägger till hälsokontrollerbör du använda alla etablerade eller befintliga hälsokontroller om möjligt. Annars kan du överväga att implementera din egen i integrationen. Lägg till följande kod i projektet MailKit.Client i en fil med namnet 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;
        }
    }
}

Koden ovan definierar klassen MailKitClientSettings med:

  • Endpoint egenskap som representerar anslutningssträngen till SMTP-server.
  • DisableHealthChecks egenskap som avgör om hälsokontroller är aktiverade.
  • DisableTracing egenskap som avgör om spårning är aktiverat.
  • DisableMetrics egenskap som avgör om mått är aktiverade.

Parsa anslutningssträngslogik

Inställningsklassen innehåller också en ParseConnectionString metod som parsar anslutningssträngen till en giltig Uri. Konfigurationen förväntas anges i följande format:

  • ConnectionStrings:<connectionName>: Anslutningssträngen till SMTP-server.
  • MailKit:Client:ConnectionString: Anslutningssträngen till SMTP-server.

Om inget av dessa värden anges genereras ett undantag.

Exponera client funktioner

Målet med .NET Aspire integrationer är att exponera det underliggande client biblioteket för konsumenter via beroendeinjektion. Med MailKit och i det här exemplet är klassen SmtpClient det du vill exponera. Du omsluter inte några funktioner, utan mappar snarare konfigurationsinställningar till en SmtpClient-klass. Det är vanligt att exponera både standardregistreringar och registreringar för "keyed-service" vid integrationer. Standardregistreringar används när det bara finns en instans av en tjänst och registreringar av nyckelade tjänster används när det finns flera instanser av en tjänst. Ibland använder du ett fabriksmönster för att uppnå flera registreringar av samma typ. Lägg till följande kod i projektet MailKit.Client i en fil med namnet 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();
    }
}

Klassen MailKitClientFactory är en fabrik som skapar en ISmtpClient-instans baserat på konfigurationsinställningarna. Den ansvarar för att returnera en ISmtpClient implementering som har en aktiv anslutning till en konfigurerad SMTP-server. Därefter måste du exponera funktionaliteten så att konsumenterna kan registrera den här fabriken med beroendeinjektionskontainern. Lägg till följande kod i projektet MailKit.Client i en fil med namnet 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));
        }
    }
}

Föregående kod lägger till två tilläggsmetoder på den IHostApplicationBuilder typen, en för standardregistreringen av MailKit och en annan för nyckelregistrering av MailKit.

Tips

Tilläggsmetoder för .NET.NET Aspire integreringar bör utöka IHostApplicationBuilder typ och följa Add<MeaningfulName> namngivningskonvention där <MeaningfulName> är den typ eller funktion som du lägger till. I den här artikeln används AddMailKitClient-tilläggsmetoden för att lägga till MailKit-client. Det är förmodligen mer i linje med den officiella vägledningen för att använda AddMailKitSmtpClient i stället för AddMailKitClient, eftersom detta bara registrerar SmtpClient och inte hela MailKit-biblioteket.

Båda tilläggen förlitar sig slutligen på den privata AddMailKitClient-metoden för att registrera MailKitClientFactory med containern för beroendeinmatning som en begränsad tjänst. Anledningen till att registrera MailKitClientFactory som en begränsad tjänst är att anslutningsåtgärderna anses vara dyra och bör återanvändas inom samma omfång där det är möjligt. Med andra ord bör samma ISmtpClient instans användas för en enskild begäran. Fabriken håller fast vid instansen av SmtpClient som den skapar och tar bort den.

Konfigurationsbindning

En av de första sakerna som den privata implementeringen av AddMailKitClient metoder gör är att binda konfigurationsinställningarna till klassen MailKitClientSettings. Inställningsklassen instansieras och sedan anropas Bind med det specifika avsnittet i konfigurationen. Sedan anropas den valfria configureSettings-delegeringen med de aktuella inställningarna. Detta gör det möjligt för konsumenten att ytterligare konfigurera inställningarna, vilket säkerställer att manuella kodinställningar respekteras jämfört med konfigurationsinställningarna. Därefter, beroende på om serviceKey värdet angavs, bör MailKitClientFactory registreras med containern för beroendeinmatning som antingen en standardtjänst eller en nyckelbaserad tjänst.

Viktig

Det är avsiktligt att implementationFactory överlagring anropas när tjänster registreras. Metoden CreateMailKitClientFactory utlöser när konfigurationen är ogiltig. Detta säkerställer att skapandet av MailKitClientFactory skjuts upp tills det behövs, och det förhindrar att appen kraschar innan loggning är tillgänglig.

Registreringen av hälsokontroller och telemetri beskrivs lite mer detaljerat i följande avsnitt.

Lägga till hälsokontroller

Hälsokontroller är ett sätt att övervaka hälsotillståndet för en integrering. Med MailKit kan du kontrollera om anslutningen till SMTP-server är felfri. Lägg till följande kod i projektet MailKit.Client i en fil med namnet 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);
        }
    }
}

Föregående implementering av hälsokontroll:

  • Implementerar IHealthCheck-gränssnittet.
  • Accepterar MailKitClientFactory som en primär konstruktorparameter.
  • Uppfyller metoden CheckHealthAsync genom att:
    • Försöker hämta en ISmtpClient instans från factory. Om det lyckas returneras HealthCheckResult.Healthy.
    • Om ett undantag utlöses returneras HealthCheckResult.Unhealthy.

Som tidigare delats vid registreringen av MailKitClientFactoryär MailKitHealthCheck villkorligt registrerat med IHeathChecksBuilder:

if (settings.DisableHealthChecks is false)
{
    builder.Services.AddHealthChecks()
        .AddCheck<MailKitHealthCheck>(
            name: serviceKey is null ? "MailKit" : $"MailKit_{connectionName}",
            failureStatus: default,
            tags: []);
}

Konsumenten kan välja att utelämna hälsokontroller genom att ange egenskapen DisableHealthChecks till true i konfigurationen. Ett vanligt mönster för integreringar är att ha valfria funktioner och .NET.NET Aspire integreringar uppmuntrar starkt dessa typer av konfigurationer. Mer information om hälsokontroller och ett arbetsexempel som innehåller ett användargränssnitt finns i .NET AspireASP.NET Core HealthChecksUI-exempel.

Anslut telemetri

Bästa praxis är att biblioteket MailKit client exponerar telemetri. .NET .NET Aspire kan dra nytta av den här telemetrin och visa den på .NET.NET Aspire instrumentpanelen. Beroende på om spårning och mått är aktiverade eller inte är telemetrin kopplad enligt följande kodfragment:

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));
}

Uppdatera nyhetsbrevstjänsten

När integrationsbiblioteket har skapats kan du nu uppdatera nyhetsbrevstjänsten för att använda MailKit-client. Det första steget är att lägga till en referens till MailKit.Client-projektet. Lägg till MailKit.Client.csproj projektreferens till MailDevResource.NewsletterService-projektet:

dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference MailKit.Client/MailKit.Client.csproj

Lägg sedan till en referens till ServiceDefaults-projektet:

dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference MailDevResource.ServiceDefaults/MailDevResource.ServiceDefaults.csproj

Det sista steget är att ersätta den befintliga Program.cs-filen i MailDevResource.NewsletterService-projektet med följande C#-kod:

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();

De viktigaste ändringarna i föregående kod är:

  • De uppdaterade using-instruktionerna som innehåller namnrymderna MailKit.Client, MailKit.Net.Smtpoch MimeKit.
  • Ersättning av registreringen för den officiella .NETSmtpClient med anropet till AddMailKitClient tilläggsmetod.
  • Ersättningen av både /subscribe och /unsubscribe mappa postanrop för att i stället mata in MailKitClientFactory och använda instansen ISmtpClient för att skicka e-postmeddelandet.

Kör exemplet

Nu när du har skapat MailKit-client integrering och uppdaterat nyhetsbrevstjänsten så att den används kan du köra exemplet. I din IDE väljer du F5 eller kör dotnet run från rotkatalogen för lösningen för att starta programmet. Du bör se .NET.NET Aspire instrumentpanel:

.NET Aspire instrumentpanel: MailDev och nyhetsbrevsresurser körs.

När programmet har körts går du till Swagger-användargränssnittet vid https://localhost:7251/swagger och testar /subscribe- och /unsubscribe-slutpunkterna. Välj nedåtpilen för att expandera slutpunkten:

Swagger-användargränssnitt: Prenumerera på slutpunkt.

Välj sedan knappen Try it out. Ange en e-postadress och välj sedan knappen Execute.

Swagger UI: Prenumerera på slutpunkt med e-postadress.

Upprepa detta flera gånger för att lägga till flera e-postadresser. Du bör se e-postmeddelandet som skickas till MailDev inkorgen:

MailDev inkorg med flera e-postmeddelanden.

Stoppa programmet genom att välja Ctrl+C i terminalfönstret där programmet körs, eller genom att välja stoppknappen i din IDE.

Visa Telemetri för MailKit

Biblioteket MailKit client visar telemetri som kan visas på instrumentpanelen .NET Aspire. Om du vill visa telemetrin navigerar du till instrumentpanelen .NET.NET Aspire på https://localhost:7251. Välj resursen newsletter för att visa telemetrin på sidan Mått.

.NET.NET Aspire instrumentpanel: MailKit-telemetri.

Öppna Swagger-användargränssnittet igen och gör några begäranden till /subscribe och /unsubscribe slutpunkter. Gå sedan tillbaka till instrumentpanelen .NET.NET Aspire och välj resursen newsletter. Välj ett mått under noden mailkit.net.smtp, till exempel mailkit.net.smtp.client.operation.count. Du bör se telemetrin för MailKit-client:

.NET.NET Aspire instrumentpanel: MailKit-telemetri för operationernas antal.

Sammanfattning

I den här artikeln har du lärt dig hur du skapar en .NET.NET Aspire integrering som använder MailKit för att skicka e-postmeddelanden. Du har också lärt dig hur du integrerar den här integreringen i appen Nyhetsbrev som du skapade tidigare. Du har lärt dig om grundprinciperna för .NET Aspire-integrationer, till exempel att exponera det underliggande client-biblioteket för konsumenter via beroendeinjektion och hur du lägger till hälsokontroller och telemetri i integrationen. Du har också lärt dig hur du uppdaterar nyhetsbrevstjänsten för att använda MailKit-client.

Gå vidare och skapa egna .NET.NET Aspire integreringar. Om du tror att det finns tillräckligt med community-värde i den integrering som du skapar kan du publicera det som ett NuGet-paket för andra att använda. Överväg dessutom att skicka en pull request till förrådet .NET AspireGitHub för övervägande att inkluderas i de officiella .NET.NET Aspire integrationerna.

Nästa steg