Creación de integraciones de hospedaje de .NET.NET Aspire personalizadas
.NET .NET Aspire mejora la experiencia de desarrollo proporcionando bloques de creación reutilizables que se pueden usar para organizar rápidamente las dependencias de la aplicación y exponerlas a su propio código. Uno de los componentes fundamentales de una aplicación basada en Aspirees el recurso . Tenga en cuenta el código siguiente:
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);
En el código anterior hay cuatro recursos representados:
-
cache
: un contenedor de Redis. -
pgserver
: un contenedor de Postgres. -
inventorydb
: una base de datos hospedada enpgserver
. -
inventoryservice
: una aplicación de ASP.NET Core.
La mayoría del código relacionado con .NET.NET Aspireque escribe el desarrollador promedio se centra en agregar recursos al modelo de aplicación y crear referencias entre ellos.
Elementos clave de un recurso personalizado de .NET.NET Aspire
La creación de un recurso personalizado en .NET.NET Aspire requiere lo siguiente:
- Tipo de recurso personalizado que implementa IResource
- Un método de extensión para IDistributedApplicationBuilder denominado
Add{CustomResource}
donde{CustomResource}
es el nombre del recurso personalizado.
Cuando el recurso personalizado requiere una configuración opcional, es posible que los desarrolladores deseen implementar With*
métodos de extensión con sufijo para que estas opciones de configuración se puedan hacer visibles mediante el patrón de constructor .
Ejemplo práctico: MailDev
Para ayudar a comprender cómo desarrollar recursos personalizados, en este artículo se muestra un ejemplo de cómo crear un recurso personalizado para MailDev. MailDev es una herramienta de código abierto que proporciona una server de correo local diseñada para permitir a los desarrolladores probar comportamientos de envío de correo electrónico dentro de su aplicación. Para obtener más información, consulte el repositorio de MailDevGitHub.
En este ejemplo, creará un nuevo proyecto de .NET Aspire como entorno de prueba para el recurso MailDev que cree. Aunque puede crear recursos personalizados en proyectos de .NET Aspire existentes, es recomendable tener en cuenta si el recurso personalizado puede usarse en varias soluciones basadas en .NET Aspirey debe desarrollarse como una integración reutilizable.
Configuración del proyecto de inicio
Cree un nuevo proyecto de .NET.NET Aspire que se use para probar el nuevo recurso que estamos desarrollando.
dotnet new aspire -o MailDevResource
cd MailDevResource
dir
Una vez creado el proyecto, debería ver una lista que contenga lo siguiente:
: la host de la aplicación de que se usa para probar el recurso personalizado. -
MailDevResource.ServiceDefaults
: el servicio de predeterminado proyecto para su uso en proyectos relacionados con el servicio. -
MailDevResource.sln
: el archivo de solución que hace referencia a ambos proyectos.
Compruebe que el proyecto puede compilarse y ejecutarse correctamente ejecutando el siguiente comando:
dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj
La salida de la consola debe ser similar a la siguiente:
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.
Seleccione el vínculo del panel de control en el explorador para ver el panel de control .NET.NET Aspire:
Presione Ctrl+C para apagar la aplicación (puede cerrar la pestaña del explorador).
Creación de una biblioteca para la extensión de recursos
.NET Aspire recursos son solo clases y métodos contenidos en una biblioteca de clases que hace referencia a la biblioteca de hospedaje de .NET Aspire (Aspire.Hosting
). Al colocar el recurso en un proyecto independiente, puede compartirlo más fácilmente entre aplicaciones basadas en .NET.NET Aspirey potencialmente empaquetarlas y compartirla en NuGet.
Cree el proyecto de biblioteca de clases denominado MailDev. Hospedar.
dotnet new classlib -o MailDev.Hosting
Agregue
Aspire.Hosting
a la biblioteca de clases como referencia de paquete.dotnet add ./MailDev.Hosting/MailDev.Hosting.csproj package Aspire.Hosting --version 9.0.0
Importante
La versión que especifique aquí debe coincidir con la versión de la carga de trabajo .NET.NET Aspire instalada.
Agregue una referencia de biblioteca de clases al proyecto MailDevResource.AppHost.
dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
Agregue un proyecto de biblioteca de clases al archivo de solución.
dotnet sln ./MailDevResource.sln add ./MailDev.Hosting/MailDev.Hosting.csproj
Una vez realizados los pasos siguientes, puede iniciar el proyecto:
dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj
Esto da como resultado una advertencia que se muestra en la consola:
.\.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]
Esto se debe a que .NET.NET Aspire trata las referencias de proyecto en el host de la aplicación como si fueran proyectos de servicio. Para indicar .NET.NET Aspire que la referencia del proyecto debe tratarse como un proyecto que no es de servicio, modifique la referencia de archivos MailDevResource.AppHostMailDevResource.AppHost.csproj al proyecto de MailDev.Hosting
para que sea la siguiente:
<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>
Ahora, al iniciar el host de la aplicación, no se muestra ninguna advertencia en la consola.
Definición de los tipos de recursos
El MailDev.Hosting biblioteca de clases contiene el tipo de recurso y los métodos de extensión para agregar el recurso al anfitrión de la aplicación. Primero debe pensar en la experiencia que quiere proporcionar a los desarrolladores al usar el recurso personalizado. En el caso de este recurso personalizado, querrá que los desarrolladores puedan escribir código como el siguiente:
var builder = DistributedApplication.CreateBuilder(args);
var maildev = builder.AddMailDev("maildev");
builder.AddProject<Projects.NewsletterService>("newsletterservice")
.WithReference(maildev);
Para ello, necesita un recurso personalizado denominado MailDevResource
que implemente IResourceWithConnectionString para que los consumidores puedan utilizarlo con la extensión WithReference para inyectar los detalles de conexión como una cadena de conexión para el MailDevy elserver.
MailDev está disponible como un recurso de contenedor, por lo que se recomienda derivar de ContainerResource para que podamos usar varias extensiones preexistentes centradas en contenedores en .NET.NET Aspire.
Reemplace el contenido del archivo Class1.cs en el proyecto de MailDev.Hosting
y cambie el nombre del archivo a MailDevResource.cs por el código siguiente:
// 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)}"
);
}
En el recurso personalizado anterior, el EndpointReference y el ReferenceExpression son ejemplos de varios tipos que implementan una colección de interfaces, como IManifestExpressionProvider, IValueProvidery IValueWithReferences. Para obtener más información sobre estos tipos y su rol en .NET.NET Aspire, consulte detalles técnicos.
Definición de las extensiones de recursos
Para facilitar a los desarrolladores el uso del recurso personalizado, es necesario agregar un método de extensión denominado AddMailDev
al proyecto de MailDev.Hosting. El método de extensión AddMailDev
es responsable de configurar el recurso para que pueda iniciarse correctamente como un contenedor.
Agregue el código siguiente a un nuevo archivo denominado MailDevResourceBuilderExtensions.cs en el proyecto MailDevHosting:
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";
}
Validación de la integración personalizada dentro del host de la aplicación
Ahora que la estructura básica del recurso personalizado está completa, es el momento de probarla en un proyecto de AppHost real. Abra el archivo Program.cs en el proyecto de MailDevResource.AppHost y actualícelo con el código siguiente:
var builder = DistributedApplication.CreateBuilder(args);
var maildev = builder.AddMailDev("maildev");
builder.Build().Run();
Después de actualizar el archivo Program.cs, inicie el proyecto host de la aplicación y abra el panel:
dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj
Después de unos instantes, el panel muestra que el recurso de maildev
se está ejecutando y un hipervínculo estará disponible que navegue a la aplicación web de MailDev, que muestra el contenido de cada correo electrónico que envía la aplicación.
El panel de .NET.NET Aspire debe ser similar al siguiente:
La aplicación web de MailDev debe ser similar a la siguiente:
Adición de un proyecto de servicio de .NET al host de la aplicación para realizar pruebas
Una vez que .NET Aspire pueda iniciar correctamente la integración de MailDev, es hora de utilizar la información de conexión de MailDev en un proyecto .NET. En .NET.NET Aspire es común que haya un paquete de alojamiento y uno o varios paquetes de componentes . Por ejemplo, tenga en cuenta lo siguiente:
-
paquete de hospedaje: se usa para representar recursos dentro del modelo de aplicación.
Aspire.Hosting.Redis
-
Paquetes de componentes: se usan para configurar y consumir bibliotecas de client.
Aspire.StackExchange.Redis
Aspire.StackExchange.Redis.DistributedCaching
Aspire.StackExchange.Redis.OutputCaching
En el caso del recurso MailDev, la plataforma .NET ya tiene un protocolo simple de transferencia de correo (SMTP) client en forma de SmtpClient. En este ejemplo se usa esta API existente por motivos de simplicidad, aunque otros tipos de recursos pueden beneficiarse de bibliotecas de integración personalizadas para ayudar a los desarrolladores.
Para probar el escenario de punta a punta, necesita un proyecto de .NET en el que se pueda insertar la información de conexión para el recurso de MailDev. Agregue un proyecto de API web:
Cree un nuevo proyecto de .NET denominado MailDevResource.NewsletterService.
dotnet new webapi --use-minimal-apis -o MailDevResource.NewsletterService
Agregue una referencia al proyecto de MailDev.Hosting.
dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
Agregue una referencia al proyecto de MailDevResource.AppHost.
dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj
Agregue el nuevo proyecto al archivo de solución.
dotnet sln ./MailDevResource.sln add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj
Una vez agregado el proyecto y se hayan actualizado las referencias, abra el Program.cs del proyecto de MailDevResource.AppHost.csproj y actualice el archivo de origen para que tenga el siguiente aspecto:
var builder = DistributedApplication.CreateBuilder(args);
var maildev = builder.AddMailDev("maildev");
builder.AddProject<Projects.MailDevResource_NewsletterService>("newsletterservice")
.WithReference(maildev);
builder.Build().Run();
Después de actualizar el archivo Program.cs, vuelva a iniciar el host de la aplicación. A continuación, compruebe que se inició el servicio newsletter y que la variable de entorno ConnectionStrings__maildev
se agregó al proceso. En la página de Recursos de
En la captura de pantalla anterior se muestran las variables de entorno del proyecto de newsletterservice
. La variable de entorno ConnectionStrings__maildev
es la cadena de conexión que el recurso maildev
insertó en el proyecto.
Uso de la cadena de conexión para enviar mensajes
Para usar los detalles de conexión SMTP que se insertaron en el proyecto de servicio de boletín, inserte una instancia de SmtpClient en el contenedor de inserción de dependencias como singleton. Agregue el código siguiente al archivo Program.cs del proyecto MailDevResource.NewsletterService para configurar el servicio singleton. En la clase Program
, inmediatamente después del comentario // Add services to the container
, agregue el código siguiente:
builder.Services.AddSingleton<SmtpClient>(sp =>
{
var smtpUri = new Uri(builder.Configuration.GetConnectionString("maildev")!);
var smtpClient = new SmtpClient(smtpUri.Host, smtpUri.Port);
return smtpClient;
});
Propina
Sin embargo, este fragmento de código se basa en el SmtpClient
oficial; este tipo está obsoleto en algunas plataformas y no se recomienda en otros. Para obtener un enfoque más moderno mediante MailKit, consulte Creación de integraciones de .NET Aspireclient personalizadas.
Para probar el client, agregue dos métodos POST simples, subscribe
y unsubscribe
, al servicio de boletín informativo. Agregue el código siguiente reemplazando la llamada "weatherforecast" MapGet
en el archivo Program.cs del proyecto MailDevResource.NewsletterService para configurar las rutas de 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);
});
Propina
Recuerde hacer referencia a los espacios de nombres System.Net.Mail
y Microsoft.AspNetCore.Mvc
en Program.cs si el editor de código no los agrega automáticamente.
Una vez actualizado el archivo Program.cs, inicie el host de la aplicación y use el explorador o curl
para alcanzar las siguientes direcciones URL (como alternativa si usa Visual Studio puede usar archivos .http
):
POST /subscribe?email=test@test.com HTTP/1.1
Host: localhost:7251
Content-Type: application/json
Para usar esta API, puede usar curl
para enviar la solicitud. El siguiente comando curl
envía una solicitud HTTP POST
al punto de conexión subscribe
y espera obtener un valor de cadena de consulta email
para suscribirse al boletín. El encabezado Content-Type
se establece en application/json
para indicar que el cuerpo de la solicitud está en formato JSON.:
curl -H "Content-Type: application/json" --request POST https://localhost:7251/subscribe?email=test@test.com
La siguiente API es el extremo unsubscribe
. Este punto de conexión se usa para cancelar la suscripción al boletín.
POST /unsubscribe?email=test@test.com HTTP/1.1
Host: localhost:7251
Content-Type: application/json
Para cancelar la suscripción al boletín, puede usar el siguiente comando de curl
, pasando un parámetro email
al punto de conexión de unsubscribe
como una cadena de consulta:
curl -H "Content-Type: application/json" --request POST https://localhost:7251/unsubscribe?email=test@test.com
Propina
Asegúrese de reemplazar el https://localhost:7251
por el puerto de localhost correcto (la dirección URL del host de la aplicación que está ejecutando).
Si esas llamadas API devuelven una respuesta correcta (HTTP 200, Ok), deberías poder seleccionar en el recurso maildev
el panel, y MailDev UI mostrará los correos electrónicos que se han enviado al punto de conexión SMTP.
Detalles técnicos
En las secciones siguientes, se describen varios detalles técnicos que son importantes para comprender al desarrollar recursos personalizados para .NET.NET Aspire.
Protección de redes
En este ejemplo, el recurso MailDev es un recurso de contenedor que se expone a la máquina host a través de HTTP y SMTP. El recurso MailDev es una herramienta de desarrollo y no está pensada para su uso en producción. Para usar HTTPS en su lugar, consulte MailDev: Configurar HTTPS.
Al desarrollar recursos personalizados que exponen puntos de conexión de red, es importante tener en cuenta las implicaciones de seguridad del recurso. Por ejemplo, si el recurso es una base de datos, es importante asegurarse de que la base de datos es segura y que la cadena de conexión no está expuesta a la red pública de Internet.
Tipo de ReferenceExpression
y EndpointReference
En el código anterior, el MailDevResource
tenía dos propiedades:
-
SmtpEndpoint
: tipo EndpointReference. -
ConnectionStringExpression
: tipo de ReferenceExpression.
Estos tipos se encuentran entre varios que se usan en .NET Aspire para representar datos de configuración, que no se finalizan hasta que el proyecto de .NET Aspire se ejecuta o se publica en la nube a través de una herramienta como Azure Developer CLI (azd
).
El problema fundamental que estos tipos ayudan a resolver, es aplazar la resolución de información de configuración concreta hasta que todas las la información está disponible.
Por ejemplo, el MailDevResource
expone una propiedad denominada ConnectionStringExpression
según lo requiera la interfaz IResourceWithConnectionString. El tipo de la propiedad se ReferenceExpression y se crea pasando una cadena interpolada al método Create.
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create(
$"smtp://{SmtpEndpoint.Property(EndpointProperty.Host)}:{SmtpEndpoint.Property(EndpointProperty.Port)}"
);
La firma del método Create es la siguiente:
public static ReferenceExpression Create(
in ExpressionInterpolatedStringHandler handler)
No es un argumento normal de String. El método usa el patrón de controlador de cadenas interpolada , para capturar la plantilla de cadena interpolada y los valores a los que se hace referencia en él para permitir el procesamiento personalizado. En el caso de .NET.NET Aspire, estos detalles se capturan en un ReferenceExpression que se puede evaluar a medida que cada valor al que se hace referencia en la cadena interpolada está disponible.
Este es el funcionamiento del flujo de ejecución:
- Un recurso que implementa IResourceWithConnectionString se agrega al modelo (por ejemplo,
AddMailDev(...)
). - El
IResourceBuilder<MailDevResource>
se pasa al WithReference que tiene una sobrecarga específica para manejar implementaciones de IResourceWithConnectionString. - El
WithReference
encapsula el recurso en una instancia de ConnectionStringReference y el objeto se captura en un EnvironmentCallbackAnnotation que se evalúa después de que se compila el proyecto de .NET.NET Aspire y comienza a ejecutarse. - A medida que el proceso que hace referencia a la cadena de conexión se inicia .NET.NET Aspire comienza a evaluar la expresión. Primero obtiene el ConnectionStringReference y llama a IValueProvider.GetValueAsync.
- El método
GetValueAsync
obtiene el valor de la propiedad ConnectionStringExpression para obtener la instancia de ReferenceExpression. - A continuación, el método IValueProvider.GetValueAsync llama a GetValueAsync para procesar la cadena interpolada capturada anteriormente.
- Dado que la cadena interpolada contiene referencias a otros tipos de referencia, como EndpointReference, también se evalúan y se sustituye el valor real, que en este momento está disponible.
Publicación de manifiestos
La interfaz IManifestExpressionProvider está diseñada para resolver el problema de compartir información de conexión entre recursos en la implementación. La solución para este problema en particular se describe en la visión general de la red del bucle interno .NET.NET Aspire. De forma similar al desarrollo local, muchos de los valores son necesarios para configurar la aplicación, pero no se pueden determinar hasta que la aplicación se implemente a través de una herramienta, como azd
(Azure Developer CLI).
Para solucionar este problema .NET.NET Aspire genera un archivo de manifiesto que azd
y otras herramientas de implementación interpretan. En lugar de especificar valores concretos para la información de conexión entre recursos, se usa una sintaxis de expresión que evalúan las herramientas de implementación. Por lo general, el archivo de manifiesto no es visible para los desarrolladores, pero es posible generar uno para la inspección manual. El comando siguiente se puede usar en el host de la aplicación para generar un manifiesto.
dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj -- --publisher manifest --output-path aspire-manifest.json
Este comando genera un archivo de manifiesto como el siguiente:
{
"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"
}
}
}
}
}
Dado que el MailDevResource
implementa IResourceWithConnectionString la lógica de publicación del manifiesto en .NET.NET Aspire sabe que, aunque MailDevResource
sea un recurso de contenedor, también necesita un campo connectionString
. El campo connectionString
hace referencia a otras partes del recurso maildev
del manifiesto para generar la cadena final:
{
// ... other content omitted.
"connectionString": "smtp://{maildev.bindings.smtp.host}:{maildev.bindings.smtp.port}"
}
.NET .NET Aspire sabe cómo formar esta cadena porque examina ConnectionStringExpression y crea la cadena final a través de la interfaz IManifestExpressionProvider (de la misma manera que se usa la interfaz IValueProvider).
El MailDevResource
se incluye automáticamente en el manifiesto porque se deriva de ContainerResource. Los autores de recursos pueden optar por suprimir la salida del contenido en el manifiesto mediante el método de extensión ExcludeFromManifest en el generador de recursos.
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
}
Se debe tener en cuenta detenidamente si el recurso debe estar presente en el manifiesto o si se debe suprimir. Si se está agregando el recurso al manifiesto, debe configurarse de modo que sea seguro y protegido para usar.
Resumen
En el tutorial de recursos personalizados, ha aprendido a crear un recurso de .NET Aspire personalizado que usa una aplicación en contenedor existente (MailDev). Después, lo ha usado para mejorar la experiencia de desarrollo local, ya que facilita la prueba de las funcionalidades de correo electrónico que se pueden usar dentro de una aplicación. Estos aprendizajes se pueden aplicar para crear otros recursos personalizados que se pueden usar en aplicaciones basadas en .NET.NET Aspire. Este ejemplo específico no incluía ninguna integración personalizada, pero es posible crear integraciones personalizadas para facilitar a los desarrolladores el uso del recurso. En este escenario, pudo confiar en la clase SmtpClient
existente en la plataforma de .NET para enviar correos electrónicos.