Condividi tramite


Creare integrazioni di hosting di .NET.NET Aspire personalizzate

.NET .NET Aspire migliora l'esperienza di sviluppo fornendo blocchi predefiniti riutilizzabili che possono essere usati per organizzare rapidamente le dipendenze dell'applicazione ed esporle al proprio codice. Uno dei blocchi predefiniti di base di un'applicazione basata su Aspireè la risorsa . Considerare il codice seguente:

var builder = DistributedApplication.CreateBuilder(args);

var redis = builder.AddRedis("cache");

var db = builder.AddPostgres("pgserver")
                .AddDatabase("inventorydb");

builder.AddProject<Projects.InventoryService>("inventoryservice")
       .WithReference(redis)
       .WithReference(db);

Nel codice precedente sono rappresentate quattro risorse:

  1. cache: un contenitore Redis.
  2. pgserver: contenitore Postgres.
  3. inventorydb: Un database ospitato su pgserver.
  4. inventoryservice: un'applicazione ASP.NET Core.

La maggior parte del codice correlato .NET.NET Aspireche lo sviluppatore medio scrive, si concentra sull'aggiunta di risorse al modello di app e la creazione di riferimenti tra di essi.

Elementi chiave di una risorsa personalizzata .NET.NET Aspire

La creazione di una risorsa personalizzata in .NET.NET Aspire richiede quanto segue:

  1. Tipo di risorsa personalizzato che implementa IResource
  2. Metodo di estensione per IDistributedApplicationBuilder denominato Add{CustomResource} in cui {CustomResource} è il nome della risorsa personalizzata.

Quando la risorsa personalizzata richiede una configurazione facoltativa, gli sviluppatori potrebbero voler implementare metodi di estensione con suffisso With* che rendano individuabili queste opzioni di configurazione usando il pattern builder .

Esempio pratico: MailDev

Per comprendere come sviluppare risorse personalizzate, questo articolo illustra un esempio di come creare una risorsa personalizzata per MailDev. MailDev è uno strumento open source che fornisce un server di posta elettronica locale progettato per consentire agli sviluppatori di testare i comportamenti di invio di posta elettronica all'interno dell'app. Per altre informazioni, vedere repository MailDevGitHub.

In questo esempio viene creato un nuovo progetto di .NET Aspire come ambiente di test per la risorsa MailDev creata. Anche se è possibile creare risorse personalizzate nei progetti di .NET Aspire esistenti, è consigliabile valutare se la risorsa personalizzata può essere usata in più soluzioni basate su .NET Aspiree deve essere sviluppata come integrazione riutilizzabile.

Configurare il progetto iniziale

Crea un nuovo progetto .NET.NET Aspire utilizzato per testare la nuova risorsa che stiamo sviluppando.

dotnet new aspire -o MailDevResource
cd MailDevResource
dir

Dopo aver creato il progetto, verrà visualizzato un elenco contenente quanto segue:

  • MailDevResource.AppHost: l'host dell'applicazione utilizzato per testare la risorsa personalizzata.
  • MailDevResource.ServiceDefaults: il servizio imposta di default il progetto per i progetti correlati al servizio.
  • MailDevResource.sln: file di soluzione che fa riferimento a entrambi i progetti.

Verificare che il progetto possa compilare ed eseguire correttamente eseguendo il comando seguente:

dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj

L'output della console dovrebbe essere simile al seguente:

Building...
info: Aspire.Hosting.DistributedApplication[0]
      Aspire version: 9.0.0
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application starting.
info: Aspire.Hosting.DistributedApplication[0]
      Application host directory is:
      ..\docs-aspire\docs\extensibility\snippets\MailDevResource\MailDevResource.AppHost
info: Aspire.Hosting.DistributedApplication[0]
      Now listening on: https://localhost:17251
info: Aspire.Hosting.DistributedApplication[0]
      Login to the dashboard at https://localhost:17251/login?t=928db244c720c5022a7a9bf5cf3a3526
info: Aspire.Hosting.DistributedApplication[0]
      Distributed application started. Press Ctrl+C to shut down.

Selezionare il collegamento dashboard nel browser per visualizzare il dashboard .NET.NET Aspire:

Screenshot del dashboard vuoto .NET.NET Aspire per il progetto di test.

Premere CTRL+C per arrestare l'app (è possibile chiudere la scheda del browser).

Creare una libreria per l'estensione della risorsa

.NET Aspire risorse sono solo classi e metodi contenuti all'interno di una libreria di classi che fa riferimento alla libreria di hosting .NET Aspire (Aspire.Hosting). Inserendo la risorsa in un progetto separato, è possibile condividerla più facilmente tra le app basate su .NET.NET Aspiree potenzialmente creare un pacchetto e condividerla in NuGet.

  1. Creare il progetto di libreria di classi denominato MailDev. Hosting.

    dotnet new classlib -o MailDev.Hosting
    
  2. Aggiungere Aspire.Hosting alla libreria delle classi come riferimento del pacchetto.

    dotnet add ./MailDev.Hosting/MailDev.Hosting.csproj package Aspire.Hosting --version 9.0.0
    

    Importante

    La versione specificata qui deve corrispondere alla versione del carico di lavoro .NET.NET Aspire installato.

  3. Aggiungi il riferimento alla libreria di classi al progetto MailDevResource.AppHost.

    dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
    
  4. Aggiungere un progetto di libreria di classi al file della soluzione.

    dotnet sln ./MailDevResource.sln add ./MailDev.Hosting/MailDev.Hosting.csproj
    

Dopo aver eseguito i passaggi seguenti, è possibile avviare il progetto:

dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj

Viene visualizzato un avviso nella console:

.\.nuget\packages\aspire.hosting.apphost\9.0.0\build\Aspire.Hosting.AppHost.targets(174,5): warning ASPIRE004: '..\MailDev.Hosting\MailDev.Hosting.csproj' is referenced by an A
spire Host project, but it is not an executable. Did you mean to set IsAspireProjectResource="false"? [D:\source\repos\docs-aspire\docs\extensibility\snippets\MailDevResource\MailDevResource.AppHost\MailDevRe
source.AppHost.csproj]

Ciò è dovuto al fatto che .NET.NET Aspire considera i riferimenti al progetto nell'host dell'app come se fossero progetti di servizio. Per indicare a .NET.NET Aspire che il riferimento al progetto deve essere trattato come un progetto non di servizio, modificare il riferimento ai file di MailDevResource.AppHostMailDevResource.AppHost.csproj per il progetto MailDev.Hosting nel modo seguente:

<ItemGroup>
  <!-- The IsAspireProjectResource attribute tells .NET Aspire to treat this 
       reference as a standard project reference and not attempt to generate
       a metadata file -->
  <ProjectReference Include="..\MailDev.Hosting\MailDev.Hosting.csproj"
                    IsAspireProjectResource="false" />
</ItemGroup>

Quando si avvia l'host dell'app, non viene visualizzato alcun avviso nella console.

Definire i tipi di risorse

Oggetto MailDev. L'hosting libreria di classi contiene il tipo di risorsa e i metodi di estensione per l'aggiunta della risorsa all'host dell'app. È consigliabile considerare prima di tutto l'esperienza che si vuole offrire agli sviluppatori quando si usa la risorsa personalizzata. Nel caso di questa risorsa personalizzata, si vuole che gli sviluppatori possano scrivere codice simile al seguente:

var builder = DistributedApplication.CreateBuilder(args);

var maildev = builder.AddMailDev("maildev");

builder.AddProject<Projects.NewsletterService>("newsletterservice")
       .WithReference(maildev);

A tale scopo, è necessaria una risorsa personalizzata denominata MailDevResource che implementa IResourceWithConnectionString in modo che i consumatori possano usarla con l'estensione WithReference per inserire i dettagli della connessione per il MailDevserver come stringa di connessione.

MailDev è disponibile come risorsa contenitore, quindi vorrai anche derivare da ContainerResource per poter utilizzare varie estensioni preesistenti incentrate sui contenitori in .NET.NET Aspire.

Sostituire il contenuto del file Class1.cs nel progetto MailDev.Hosting e rinominare il file in MailDevResource.cs con il codice seguente:

// For ease of discovery, resource types should be placed in
// the Aspire.Hosting.ApplicationModel namespace. If there is
// likelihood of a conflict on the resource name consider using
// an alternative namespace.
namespace Aspire.Hosting.ApplicationModel;

public sealed class MailDevResource(string name) : ContainerResource(name), IResourceWithConnectionString
{
    // Constants used to refer to well known-endpoint names, this is specific
    // for each resource type. MailDev exposes an SMTP endpoint and a HTTP
    // endpoint.
    internal const string SmtpEndpointName = "smtp";
    internal const string HttpEndpointName = "http";

    // An EndpointReference is a core .NET Aspire type used for keeping
    // track of endpoint details in expressions. Simple literal values cannot
    // be used because endpoints are not known until containers are launched.
    private EndpointReference? _smtpReference;

    public EndpointReference SmtpEndpoint =>
        _smtpReference ??= new(this, SmtpEndpointName);

    // Required property on IResourceWithConnectionString. Represents a connection
    // string that applications can use to access the MailDev server. In this case
    // the connection string is composed of the SmtpEndpoint endpoint reference.
    public ReferenceExpression ConnectionStringExpression =>
        ReferenceExpression.Create(
            $"smtp://{SmtpEndpoint.Property(EndpointProperty.Host)}:{SmtpEndpoint.Property(EndpointProperty.Port)}"
        );
}

Nella risorsa personalizzata precedente, le EndpointReference e le ReferenceExpression sono esempi di diversi tipi che implementano una raccolta di interfacce, ad esempio IManifestExpressionProvider, IValueProvidere IValueWithReferences. Per ulteriori informazioni su questi tipi e sul loro ruolo in .NET.NET Aspire, consultare i dettagli tecnici .

Definire le estensioni delle risorse

Per semplificare l'uso della risorsa personalizzata da parte degli sviluppatori, è necessario aggiungere al progetto MailDev.Hosting un metodo di estensione denominato AddMailDev. Il metodo di estensione AddMailDev è responsabile della configurazione della risorsa in modo che possa essere avviato correttamente come contenitore.

Aggiungere il codice seguente a un nuovo file denominato MailDevResourceBuilderExtensions.cs nel progetto MailDev.Hosting.

using Aspire.Hosting.ApplicationModel;

// Put extensions in the Aspire.Hosting namespace to ease discovery as referencing
// the .NET Aspire hosting package automatically adds this namespace.
namespace Aspire.Hosting;

public static class MailDevResourceBuilderExtensions
{
    /// <summary>
    /// Adds the <see cref="MailDevResource"/> to the given
    /// <paramref name="builder"/> instance. Uses the "2.1.0" tag.
    /// </summary>
    /// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
    /// <param name="name">The name of the resource.</param>
    /// <param name="httpPort">The HTTP port.</param>
    /// <param name="smtpPort">The SMTP port.</param>
    /// <returns>
    /// An <see cref="IResourceBuilder{MailDevResource}"/> instance that
    /// represents the added MailDev resource.
    /// </returns>
    public static IResourceBuilder<MailDevResource> AddMailDev(
        this IDistributedApplicationBuilder builder,
        string name,
        int? httpPort = null,
        int? smtpPort = null)
    {
        // The AddResource method is a core API within .NET Aspire and is
        // used by resource developers to wrap a custom resource in an
        // IResourceBuilder<T> instance. Extension methods to customize
        // the resource (if any exist) target the builder interface.
        var resource = new MailDevResource(name);

        return builder.AddResource(resource)
                      .WithImage(MailDevContainerImageTags.Image)
                      .WithImageRegistry(MailDevContainerImageTags.Registry)
                      .WithImageTag(MailDevContainerImageTags.Tag)
                      .WithHttpEndpoint(
                          targetPort: 1080,
                          port: httpPort,
                          name: MailDevResource.HttpEndpointName)
                      .WithEndpoint(
                          targetPort: 1025,
                          port: smtpPort,
                          name: MailDevResource.SmtpEndpointName);
    }
}

// This class just contains constant strings that can be updated periodically
// when new versions of the underlying container are released.
internal static class MailDevContainerImageTags
{
    internal const string Registry = "docker.io";

    internal const string Image = "maildev/maildev";

    internal const string Tag = "2.1.0";
}

Convalidare l'integrazione personalizzata all'interno dell'host dell'app

Ora che la struttura di base per la risorsa personalizzata è stata completata, è possibile testarla in un progetto AppHost reale. Aprire il file Program.cs nel progetto MailDevResource.AppHost e aggiornarlo con il codice seguente:

var builder = DistributedApplication.CreateBuilder(args);

var maildev = builder.AddMailDev("maildev");

builder.Build().Run();

Dopo aver aggiornato il file Program.cs, avviare il progetto host dell'app e aprire il dashboard:

dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj

Dopo alcuni istanti il dashboard mostra che la risorsa maildev è in esecuzione e sarà disponibile un collegamento ipertestuale che passa all'app Web MailDev, che mostra il contenuto di ogni messaggio di posta elettronica inviato dall'app.

Il dashboard .NET.NET Aspire dovrebbe essere simile al seguente:

MailDev risorsa visibile nel dashboard di .NET Aspire.

L'app Web MailDev dovrebbe essere simile alla seguente:

MailDev'interfaccia utente basata sul Web in esecuzione come contenitore gestito da .NET Aspire.

Aggiungere un progetto di servizio .NET all'host dell'app per il test

Quando .NET Aspire riesce a lanciare con successo l'integrazione MailDev, è il momento di utilizzare le informazioni di connessione per MailDev all'interno di un progetto di .NET. In .NET.NET Aspire è comune che esista un pacchetto di hosting e uno o più pacchetti di componenti . Si consideri ad esempio:

  • pacchetto di hosting: usato per rappresentare le risorse all'interno del modello di app.
    • Aspire.Hosting.Redis
  • pacchetti di componenti: usati per configurare e utilizzare le librerie di client.
    • Aspire.StackExchange.Redis
    • Aspire.StackExchange.Redis.DistributedCaching
    • Aspire.StackExchange.Redis.OutputCaching

Nel caso della risorsa MailDev, la piattaforma .NET dispone già di un semplice client SMTP (Mail Transfer Protocol) sotto forma di SmtpClient. In questo esempio si usa questa API esistente per semplicità, anche se altri tipi di risorse possono trarre vantaggio dalle librerie di integrazione personalizzate per aiutare gli sviluppatori.

Per testare lo scenario end-to-end, è necessario un progetto .NET in cui è possibile inserire le informazioni di connessione per la risorsa MailDev. Aggiungere un progetto API Web:

  1. Creare un nuovo progetto .NET denominato MailDevResource.NewsletterService.

    dotnet new webapi --use-minimal-apis -o MailDevResource.NewsletterService
    
  2. Aggiungere un riferimento al progetto MailDev.Hosting.

    dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
    
  3. Aggiungere un riferimento al progetto MailDevResource.AppHost.

    dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj
    
  4. Aggiungere il nuovo progetto al file della soluzione.

    dotnet sln ./MailDevResource.sln add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj
    

Dopo aver aggiunto il progetto e aver aggiornato i riferimenti, aprire il Program.cs del progetto MailDevResource.AppHost.csproj e aggiornare il file di origine in modo che sia simile al seguente:

var builder = DistributedApplication.CreateBuilder(args);

var maildev = builder.AddMailDev("maildev");

builder.AddProject<Projects.MailDevResource_NewsletterService>("newsletterservice")
       .WithReference(maildev);

builder.Build().Run();

Dopo aver aggiornato il file Program.cs, avviare di nuovo l'host dell'app. Verificare quindi che il servizio newsletter sia stato avviato e che la variabile di ambiente ConnectionStrings__maildev sia stata aggiunta al processo. Nella pagina Risorse, trova la riga newsletterservice e seleziona il collegamento Visualizza nella colonna Dettagli.

Variabili di ambiente per il servizio Newsletter in .NET.NET Aspire Dashboard.

Lo screenshot precedente mostra le variabili di ambiente per il progetto newsletterservice. La variabile di ambiente ConnectionStrings__maildev è la stringa di connessione inserita nel progetto dalla risorsa maildev.

Usare la stringa di connessione per inviare messaggi

Per usare i dettagli di connessione SMTP inseriti nel progetto di servizio newsletter, si deve inserire un'istanza di SmtpClient nel contenitore di iniezione delle dipendenze come singleton. Aggiungere il codice seguente al file Program.cs nel progetto MailDevResource.NewsletterService per configurare il servizio singleton. Nella classe Program aggiungere il codice seguente subito dopo il commento // Add services to the container:

builder.Services.AddSingleton<SmtpClient>(sp =>
{
    var smtpUri = new Uri(builder.Configuration.GetConnectionString("maildev")!);

    var smtpClient = new SmtpClient(smtpUri.Host, smtpUri.Port);

    return smtpClient;
});

Suggerimento

Questo frammento di codice si basa sul SmtpClientufficiale, tuttavia; questo tipo è obsoleto in alcune piattaforme e non consigliato in altri. Per un approccio più moderno usando MailKit, vedere Creare integrazioni di .NET Aspireclient personalizzate.

Per testare il client, aggiungere due semplici metodi subscribe e unsubscribe POST al servizio newsletter. Aggiungere il codice seguente per sostituire la chiamata "weatherforecast" MapGet nel file Program.cs del progetto MailDevResource.NewsletterService per configurare le route ASP.NET Core.

app.MapPost("/subscribe", async (SmtpClient smtpClient, string email) =>
{
    using var message = new MailMessage("newsletter@yourcompany.com", email)
    {
        Subject = "Welcome to our newsletter!",
        Body = "Thank you for subscribing to our newsletter!"
    };

    await smtpClient.SendMailAsync(message);
});

app.MapPost("/unsubscribe", async (SmtpClient smtpClient, string email) =>
{
    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 smtpClient.SendMailAsync(message);
});

Consiglio

Ricorda di fare riferimento ai namespace System.Net.Mail e Microsoft.AspNetCore.Mvc in Program.cs se l'editor di codice non li aggiunge automaticamente.

Dopo aver aggiornato il file Program.cs, avviare l'host dell'app e usare il browser oppure curl per raggiungere gli URL seguenti (in alternativa, se si usa Visual Studio è possibile usare .http file):

POST /subscribe?email=test@test.com HTTP/1.1
Host: localhost:7251
Content-Type: application/json

Per usare questa API, è possibile usare curl per inviare la richiesta. Il comando curl seguente invia una richiesta HTTP POST all'endpoint subscribe e si aspetta un valore della stringa di query email per iscriversi alla newsletter. L'intestazione Content-Type è impostata su application/json per indicare che il corpo della richiesta è in formato JSON:The Content-Type header is set to application/json to indicate that the request body is in JSON format.:

curl -H "Content-Type: application/json" --request POST https://localhost:7251/subscribe?email=test@test.com

L'API successiva è l'endpoint unsubscribe. Questo endpoint viene usato per annullare la sottoscrizione alla newsletter.

POST /unsubscribe?email=test@test.com HTTP/1.1
Host: localhost:7251
Content-Type: application/json

Per annullare la sottoscrizione alla newsletter, è possibile usare il comando curl seguente, passando un parametro email all'endpoint unsubscribe come stringa di query:

curl -H "Content-Type: application/json" --request POST https://localhost:7251/unsubscribe?email=test@test.com

Consiglio / Suggerimento / Mancia (select based on context)

Assicurati di sostituire il https://localhost:7251 con la porta corretta localhost (l'URL dell'host dell'app che stai eseguendo).

Se tali chiamate API restituiscono una risposta corretta (HTTP 200, Ok), sarà possibile selezionare nella risorsa maildev il dashboard e il MailDev UI mostrerà i messaggi di posta elettronica inviati all'endpoint SMTP.

messaggi di posta elettronica visibili nell'interfaccia utente MailDev

Dettagli tecnici

Nelle sezioni seguenti vengono illustrati vari dettagli tecnici che sono importanti per comprendere quando si sviluppano risorse personalizzate per .NET.NET Aspire.

Rete sicura

In questo esempio, la risorsa MailDev è una risorsa contenitore esposta al computer host tramite HTTP e SMTP. La risorsa MailDev è uno strumento di sviluppo e non è destinata all'uso in produzione. Per usare invece HTTPS, vedere MailDev: Configurare https.

Quando si sviluppano risorse personalizzate che espongono endpoint di rete, è importante considerare le implicazioni di sicurezza della risorsa. Ad esempio, se la risorsa è un database, è importante assicurarsi che il database sia sicuro e che la stringa di connessione non sia esposta alla rete Internet pubblica.

Il tipo ReferenceExpression e EndpointReference

Nel codice precedente il MailDevResource aveva due proprietà:

Questi tipi sono tra i diversi che vengono usati in .NET Aspire per rappresentare i dati di configurazione, che non vengono finalizzati fino a quando il progetto di .NET Aspire non viene eseguito o pubblicato nel cloud tramite uno strumento come Azure Developer CLI (azd).

Il problema fondamentale che questi tipi aiutano a risolvere, sta rinviando la risoluzione delle informazioni di configurazione concrete fino a tutte le le informazioni sono disponibili.

Ad esempio, il MailDevResource espone una proprietà denominata ConnectionStringExpression come richiesto dall'interfaccia IResourceWithConnectionString. Il tipo della proprietà viene ReferenceExpression e viene creato passando una stringa interpolata al metodo Create.

public ReferenceExpression ConnectionStringExpression =>
    ReferenceExpression.Create(
        $"smtp://{SmtpEndpoint.Property(EndpointProperty.Host)}:{SmtpEndpoint.Property(EndpointProperty.Port)}"
    );

La firma per il metodo Create è la seguente:

public static ReferenceExpression Create(
    in ExpressionInterpolatedStringHandler handler)

Non si tratta di un argomento String normale. Il metodo usa il modello di gestore di stringhe interpolato , per acquisire il modello di stringa interpolata e i valori a cui fa riferimento per consentire l'elaborazione personalizzata. Nel caso di .NET.NET Aspire, questi dettagli vengono acquisiti in un ReferenceExpression che può essere valutato quando ogni valore menzionato nella stringa interpolata diventa disponibile.

Ecco come funziona il flusso di esecuzione:

  1. Una risorsa che implementa IResourceWithConnectionString viene aggiunta al modello , ad esempio AddMailDev(...).
  2. Il IResourceBuilder<MailDevResource> viene passato al WithReference che dispone di un sovraccarico speciale per la gestione delle implementazioni IResourceWithConnectionString.
  3. Il WithReference avvolge la risorsa in un'istanza di ConnectionStringReference e l'oggetto viene catturato in un EnvironmentCallbackAnnotation che viene valutato dopo che il progetto .NET.NET Aspire è stato compilato e avviato.
  4. Quando il processo che fa riferimento alla stringa di connessione inizia .NET.NET Aspire inizia a valutare l'espressione. Prima ottiene il ConnectionStringReference e poi chiama IValueProvider.GetValueAsync.
  5. Il metodo GetValueAsync ottiene il valore della proprietà ConnectionStringExpression per ottenere l'istanza di ReferenceExpression.
  6. Il metodo IValueProvider.GetValueAsync chiama quindi GetValueAsync per elaborare la stringa interpolata acquisita in precedenza.
  7. Poiché la stringa interpolata contiene riferimenti ad altri tipi di riferimento, ad esempio EndpointReference vengono valutati e sostituiti con valori reali( che in questo momento sono ora disponibili).

Pubblicazione del manifesto

L'interfaccia IManifestExpressionProvider è progettata per risolvere il problema di condivisione delle informazioni di connessione tra le risorse in fase di distribuzione. La soluzione per questo particolare problema è descritta nella panoramica della rete di ciclo interno .NET.NET Aspire. Analogamente allo sviluppo locale, molti dei valori sono necessari per configurare l'app, ma non possono essere determinati fino a quando l'app non viene distribuita tramite uno strumento, ad esempio azd (Azure Developer CLI).

Per risolvere questo problema .NET.NET Aspire produce un file manifesto che azd e altri strumenti di distribuzione interpretano. Anziché specificare valori concreti per le informazioni di connessione tra le risorse viene usata una sintassi di espressione che gli strumenti di distribuzione valutano. In genere il file manifesto non è visibile agli sviluppatori, ma è possibile generarne uno per l'ispezione manuale. Il comando seguente può essere usato sull'host dell'applicazione per produrre un manifest.

dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj -- --publisher manifest --output-path aspire-manifest.json

Questo comando produce un file manifesto simile al seguente:

{
  "resources": {
    "maildev": {
      "type": "container.v0",
      "connectionString": "smtp://{maildev.bindings.smtp.host}:{maildev.bindings.smtp.port}",
      "image": "docker.io/maildev/maildev:2.1.0",
      "bindings": {
        "http": {
          "scheme": "http",
          "protocol": "tcp",
          "transport": "http",
          "targetPort": 1080
        },
        "smtp": {
          "scheme": "tcp",
          "protocol": "tcp",
          "transport": "tcp",
          "targetPort": 1025
        }
      }
    },
    "newsletterservice": {
      "type": "project.v0",
      "path": "../MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj",
      "env": {
        "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
        "OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true",
        "OTEL_DOTNET_EXPERIMENTAL_OTLP_RETRY": "in_memory",
        "ASPNETCORE_FORWARDEDHEADERS_ENABLED": "true",
        "ConnectionStrings__maildev": "{maildev.connectionString}"
      },
      "bindings": {
        "http": {
          "scheme": "http",
          "protocol": "tcp",
          "transport": "http"
        },
        "https": {
          "scheme": "https",
          "protocol": "tcp",
          "transport": "http"
        }
      }
    }
  }
}

Poiché il MailDevResource implementa la IResourceWithConnectionString logica di pubblicazione del manifesto, .NET.NET Aspire sa che anche se MailDevResource è una risorsa contenitore, necessita anche di un campo connectionString. Il campo connectionString fa riferimento ad altre parti della risorsa maildev nel manifesto per produrre la stringa finale:

{
    // ... other content omitted.
    "connectionString": "smtp://{maildev.bindings.smtp.host}:{maildev.bindings.smtp.port}"
}

.NET .NET Aspire è in grado di formare questa stringa perché esamina ConnectionStringExpression e compila la stringa finale tramite l'interfaccia IManifestExpressionProvider (in modo analogo all'interfaccia IValueProvider).

Il MailDevResource viene incluso automaticamente nel manifesto perché è derivato da ContainerResource. Gli autori di risorse possono scegliere di sopprimere l'output del contenuto nel manifesto utilizzando il metodo di estensione ExcludeFromManifest sul generatore di risorse.

public static IResourceBuilder<MailDevResource> AddMailDev(
    this IDistributedApplicationBuilder builder, 
    string name,
    int? httpPort = null,
    int? smtpPort = null)
{
    var resource = new MailDevResource(name);

    return builder.AddResource(resource)
                  .WithImage(MailDevContainerImageTags.Image)
                  .WithImageRegistry(MailDevContainerImageTags.Registry)
                  .WithImageTag(MailDevContainerImageTags.Tag)
                  .WithHttpEndpoint(
                      targetPort: 1080,
                      port: httpPort,
                      name: MailDevResource.HttpEndpointName)
                  .WithEndpoint(
                      targetPort: 1025,
                      port: smtpPort,
                      name: MailDevResource.SmtpEndpointName)
                  .ExcludeFromManifest(); // This line was added
}

È necessario considerare attentamente se la risorsa deve essere presente nel manifesto o se deve essere eliminata. Se la risorsa viene aggiunta al manifesto, deve essere configurata in modo che sia sicura e sicura da usare.

Sommario

Nell'esercitazione sulle risorse personalizzate si è appreso come creare una risorsa di .NET Aspire personalizzata che usa un'applicazione in contenitori esistente (MailDev). È stato quindi usato per migliorare l'esperienza di sviluppo locale semplificando il test delle funzionalità di posta elettronica che potrebbero essere usate all'interno di un'app. Queste informazioni possono essere applicate alla compilazione di altre risorse personalizzate che possono essere usate nelle applicazioni basate su .NET.NET Aspire. Questo esempio specifico non includeva integrazioni personalizzate, ma è possibile creare integrazioni personalizzate per semplificare l'uso della risorsa da parte degli sviluppatori. In questo scenario è stato possibile basarsi sulla classe SmtpClient esistente nella piattaforma .NET per inviare messaggi di posta elettronica.

Passaggi successivi