Criar integrações personalizadas de hospedagem .NET.NET Aspire
.NET .NET Aspire melhora a experiência de desenvolvimento fornecendo blocos de construção reutilizáveis que podem ser usados para organizar rapidamente as dependências do aplicativo e expô-las ao seu próprio código. Um dos principais blocos de construção de um aplicativo baseado em Aspireé o recurso . Considere o código abaixo:
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);
No código anterior, há quatro recursos representados:
-
cache
: um contêiner de Redis. -
pgserver
: um contêiner de Postgres. -
inventorydb
: um banco de dados hospedado nopgserver
. -
inventoryservice
: um aplicativo ASP.NET Core.
A maior parte do código relacionado a .NET.NET Aspireque um desenvolvedor médio escreve gira em torno de adicionar recursos ao modelo de aplicativo e criar referências entre eles.
Elementos-chave de um recurso personalizado .NET.NET Aspire
A criação de um recurso personalizado em .NET.NET Aspire requer o seguinte:
- Um tipo de recurso personalizado que implementa IResource
- Um método de extensão para IDistributedApplicationBuilder nomeado
Add{CustomResource}
em que{CustomResource}
é o nome do recurso personalizado.
Quando o recurso personalizado requer configuração opcional, os desenvolvedores podem querer implementar métodos de extensão com sufixos With*
para facilitar a identificação dessas opções de configuração usando o padrão do construtor .
Um exemplo prático: MailDev
Para ajudar a entender como desenvolver recursos personalizados, este artigo mostra um exemplo de como criar um recurso personalizado para MailDev. MailDev é uma ferramenta de código aberto que fornece uma server de e-mail local projetada para permitir que os desenvolvedores testem comportamentos de envio de e-mails em seus aplicativos. Para obter mais informações, consulte o repositório MailDevGitHub.
Neste exemplo, você cria um novo projeto .NET Aspire como um ambiente de teste para o recurso MailDev que você cria. Embora você possa criar recursos personalizados em projetos .NET Aspire existentes, é uma boa ideia considerar se o recurso personalizado pode ser usado em várias soluções baseadas em .NET Aspiree deve ser desenvolvido como uma integração reutilizável.
Configurar o projeto inicial
Crie um novo projeto de .NET.NET Aspire usado para testar o novo recurso que estamos desenvolvendo.
dotnet new aspire -o MailDevResource
cd MailDevResource
dir
Depois que o projeto for criado, você deverá ver uma listagem contendo o seguinte:
-
MailDevResource.AppHost
: o servidor do aplicativo usado para testar o recurso personalizado. -
MailDevResource.ServiceDefaults
: O serviço define o projeto como padrão para uso em projetos relacionados ao serviço. -
MailDevResource.sln
: o arquivo de solução que faz referência a ambos os projetos.
Verifique se o projeto pode ser compilado e executado com êxito executando o seguinte comando:
dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj
A saída do console deve ser semelhante à seguinte:
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.
Selecione o link do painel no navegador para ver o painel de .NET.NET Aspire:
Pressione Ctrl+C para desligar o aplicativo (você pode fechar a guia do navegador).
Criar biblioteca para extensão de recurso
.NET Aspire recursos são apenas classes e métodos contidos em uma biblioteca de classes que faz referência à biblioteca de hospedagem .NET Aspire (Aspire.Hosting
). Ao colocar o recurso em um projeto separado, você pode compartilhá-lo com mais facilidade entre aplicativos baseados em .NET.NET Aspiree potencialmente empacotá-lo e compartilhá-lo no NuGet.
Crie o projeto de biblioteca de classes chamado MailDev. Hospedagem.
dotnet new classlib -o MailDev.Hosting
Adicione
Aspire.Hosting
à biblioteca de classes como uma referência de pacote.dotnet add ./MailDev.Hosting/MailDev.Hosting.csproj package Aspire.Hosting --version 9.0.0
Importante
A versão especificada aqui deve corresponder à versão da carga de trabalho .NET.NET Aspire instalada.
Adicione referência de biblioteca de classes ao projeto MailDevResource.AppHost.
dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
Adicione o projeto de biblioteca de classes ao arquivo de solução.
dotnet sln ./MailDevResource.sln add ./MailDev.Hosting/MailDev.Hosting.csproj
Depois que as seguintes etapas forem executadas, você poderá iniciar o projeto:
dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj
Isso resulta em um aviso sendo exibido no 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]
Isso ocorre porque .NET.NET Aspire trata as referências de projeto no host do aplicativo como se fossem projetos de serviço. Para informar .NET.NET Aspire que a referência do projeto deve ser tratada como um projeto de não serviço, modifique a referência de arquivos MailDevResource.AppHostMailDevResource.AppHost.csproj ao projeto MailDev.Hosting
para ser o seguinte:
<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>
Agora, quando você inicia o host do aplicativo, não há nenhum aviso exibido no console.
Definir os tipos de recursos
O MailDev. Hospedar biblioteca de classes contém o tipo de recurso e os métodos de extensão para adicionar o recurso ao host do aplicativo. Você deve primeiro pensar na experiência que deseja dar aos desenvolvedores ao usar seu recurso personalizado. No caso desse recurso personalizado, você deseja que os desenvolvedores possam escrever código como o seguinte:
var builder = DistributedApplication.CreateBuilder(args);
var maildev = builder.AddMailDev("maildev");
builder.AddProject<Projects.NewsletterService>("newsletterservice")
.WithReference(maildev);
Para atingir isso, você precisa de um recurso personalizado chamado MailDevResource
que implementa IResourceWithConnectionString para que os consumidores possam usá-lo com a extensão WithReference para injetar os detalhes da conexão para o MailDevserver como string de conexão.
MailDev está disponível como um recurso de contêiner, portanto, você também desejará derivar de ContainerResource para que possamos usar várias extensões pré-existentes focadas em contêiner no .NET.NET Aspire.
Substitua o conteúdo do arquivo Class1.cs no projeto MailDev.Hosting
e renomeie o arquivo para MailDevResource.cs pelo seguinte código:
// 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)}"
);
}
No recurso personalizado anterior, os EndpointReference e ReferenceExpression são exemplos de vários tipos que implementam uma coleção de interfaces, como IManifestExpressionProvider, IValueProvidere IValueWithReferences. Para obter mais informações sobre esses tipos e sua função no .NET.NET Aspire, consulte detalhes técnicos.
Definir as extensões de recurso
Para facilitar que os desenvolvedores usem o recurso personalizado, um método de extensão chamado AddMailDev
precisa ser adicionado ao projeto MailDev.Hosting. O método de extensão AddMailDev
é responsável por configurar o recurso para que ele possa começar com êxito como um contêiner.
Adicione o código a seguir a um novo arquivo denominado MailDevResourceBuilderExtensions.cs no projeto 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";
}
Validar a integração personalizada dentro do host do aplicativo
Agora que a estrutura básica do recurso personalizado está concluída, é hora de testá-la em um projeto AppHost real. Abra o arquivo Program.cs no projeto MailDevResource.AppHost e atualize-o com o seguinte código:
var builder = DistributedApplication.CreateBuilder(args);
var maildev = builder.AddMailDev("maildev");
builder.Build().Run();
Depois de atualizar o arquivo Program.cs, inicie o projeto do host do aplicativo e abra o painel:
dotnet run --project ./MailDevResource.AppHost/MailDevResource.AppHost.csproj
Após alguns instantes, o painel mostra que o recurso de maildev
está em execução e um hiperlink estará disponível para navegar até o aplicativo Web MailDev, que mostra o conteúdo de cada email enviado pelo aplicativo.
O painel .NET.NET Aspire deve ser semelhante ao seguinte:
O aplicativo Web MailDev deve ser semelhante ao seguinte:
Adicionar um projeto de serviço .NET ao host do aplicativo para teste
Uma vez que .NET Aspire consiga iniciar com sucesso a integração MailDev, está na hora de consumir as informações de conexão do MailDev dentro de um projeto de .NET. Em .NET.NET Aspire é comum que haja um pacote de hospedagem e um ou mais pacotes de componentes . Por exemplo, considere:
-
pacote de hospedagem: usado para representar recursos no modelo de aplicativo.
Aspire.Hosting.Redis
-
Pacotes de componentes: usados para configurar e consumir bibliotecas de client.
Aspire.StackExchange.Redis
Aspire.StackExchange.Redis.DistributedCaching
Aspire.StackExchange.Redis.OutputCaching
No caso do recurso MailDev, a plataforma .NET já tem um protocolo de transferência de email simples (SMTP) client na forma de SmtpClient. Neste exemplo, você usa essa API existente para simplificar, embora outros tipos de recursos possam se beneficiar de bibliotecas de integração personalizadas para ajudar os desenvolvedores.
Para testar o cenário de ponta a ponta, você precisa de um projeto de .NET no qual podemos injetar as informações de conexão para o recurso MailDev. Adicionar um projeto de API Web:
Crie um novo projeto de .NET chamado MailDevResource.NewsletterService.
dotnet new webapi --use-minimal-apis -o MailDevResource.NewsletterService
Adicione uma referência ao projeto MailDev.Hosting.
dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
Adicione uma referência ao projeto MailDevResource.AppHost.
dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj
Adicione o novo projeto ao arquivo de solução.
dotnet sln ./MailDevResource.sln add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj
Depois que o projeto tiver sido adicionado e as referências tiverem sido atualizadas, abra a Program.cs do projeto MailDevResource.AppHost.csproj e atualize o arquivo de origem para ter a seguinte aparência:
var builder = DistributedApplication.CreateBuilder(args);
var maildev = builder.AddMailDev("maildev");
builder.AddProject<Projects.MailDevResource_NewsletterService>("newsletterservice")
.WithReference(maildev);
builder.Build().Run();
Depois de atualizar o arquivo Program.cs, inicie o host do aplicativo novamente. Em seguida, verifique se o Serviço de Boletim Informativo foi iniciado e se a variável de ambiente ConnectionStrings__maildev
foi adicionada ao processo. Na página de Recursos , localize a linha newsletterservice
e selecione o link Visualizar na coluna Detalhes.
A captura de tela anterior mostra as variáveis de ambiente do projeto newsletterservice
. A variável de ambiente ConnectionStrings__maildev
é a cadeia de conexão que foi injetada no projeto pelo recurso maildev
.
Usar cadeia de conexão para enviar mensagens
Para usar os detalhes da conexão SMTP que foram injetados no projeto do serviço de boletim informativo, você injeta uma instância de SmtpClient como um singleton no contêiner de injeção de dependência. Adicione o código a seguir ao arquivo Program.cs no projeto MailDevResource.NewsletterService para configurar o serviço singleton. Na classe Program
, imediatamente após o comentário // Add services to the container
, adicione o seguinte código:
builder.Services.AddSingleton<SmtpClient>(sp =>
{
var smtpUri = new Uri(builder.Configuration.GetConnectionString("maildev")!);
var smtpClient = new SmtpClient(smtpUri.Host, smtpUri.Port);
return smtpClient;
});
Ponta
Este trecho de código depende do SmtpClient
oficial, no entanto, esse tipo é obsoleto em algumas plataformas e não é recomendado em outras. Para obter uma abordagem mais moderna usando do MailKit, consulte Criar integrações de .NET Aspireclient personalizadas.
Para testar o client, adicione dois métodos POST subscribe
e unsubscribe
simples ao serviço de boletim informativo. Adicione o código a seguir substituindo a chamada "weatherforecast" MapGet
no arquivo Program.cs do projeto MailDevResource.NewsletterService para configurar as rotas 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);
});
Dica
Lembre-se de referenciar os namespaces System.Net.Mail
e Microsoft.AspNetCore.Mvc
no Program.cs se o editor de código não os adicionar automaticamente.
Depois que o arquivo Program.cs for atualizado, inicie o host do aplicativo e use o navegador ou curl
para acessar as SEGUINTEs URLs (como alternativa, se você estiver usando Visual Studio você pode usar arquivos .http
):
POST /subscribe?email=test@test.com HTTP/1.1
Host: localhost:7251
Content-Type: application/json
Para usar essa API, você pode usar curl
para enviar a solicitação. O comando curl
a seguir envia uma solicitação HTTP POST
para o endpoint subscribe
e espera um valor da cadeia de caracteres de consulta email
para inscrever-se no boletim informativo. O cabeçalho Content-Type
é definido como application/json
para indicar que o corpo da solicitação está no formato JSON.:
curl -H "Content-Type: application/json" --request POST https://localhost:7251/subscribe?email=test@test.com
A próxima API é o ponto de extremidade unsubscribe
. Este endpoint é usado para cancelar a inscrição na newsletter.
POST /unsubscribe?email=test@test.com HTTP/1.1
Host: localhost:7251
Content-Type: application/json
Para cancelar a assinatura do boletim informativo, você pode usar o seguinte comando curl
, passando um parâmetro email
para o ponto de extremidade unsubscribe
como uma cadeia de caracteres de consulta:
curl -H "Content-Type: application/json" --request POST https://localhost:7251/unsubscribe?email=test@test.com
Dica
Substitua a https://localhost:7251
pela porta localhost correta (a URL do host do aplicativo em execução).
Se essas chamadas à API retornarem uma resposta bem-sucedida (HTTP 200, Ok), você poderá selecionar no recurso maildev
o painel e o MailDev UI mostrará os emails que foram enviados para o ponto de extremidade SMTP.
Detalhes técnicos
Nas seções a seguir, são discutidos vários detalhes técnicos que são importantes para entender ao desenvolver recursos personalizados para .NET.NET Aspire.
Rede segura
Neste exemplo, o recurso MailDev é um recurso de contêiner que é exposto ao computador host por HTTP e SMTP. O recurso MailDev é uma ferramenta de desenvolvimento e não se destina ao uso de produção. Para, em vez disso, usar HTTPS, consulte MailDev:Configurar HTTPS.
Ao desenvolver recursos personalizados que expõem pontos de extremidade de rede, é importante considerar as implicações de segurança do recurso. Por exemplo, se o recurso for um banco de dados, é importante garantir que o banco de dados esteja seguro e que a cadeia de conexão não seja exposta à Internet pública.
O tipo ReferenceExpression
e o tipo EndpointReference
No código anterior, o MailDevResource
tinha duas propriedades:
-
SmtpEndpoint
: tipo EndpointReference. -
ConnectionStringExpression
: tipo ReferenceExpression.
Esses tipos estão entre vários que são usados em todo
O problema fundamental que esses tipos ajudam a resolver é adiar a resolução de informações concretas de configuração até todos os as informações estiverem disponíveis.
Por exemplo, o MailDevResource
expõe uma propriedade chamada ConnectionStringExpression
conforme exigido pela interface IResourceWithConnectionString. O tipo da propriedade é ReferenceExpression e é criado passando uma cadeia de caracteres interpolada para o método Create.
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create(
$"smtp://{SmtpEndpoint.Property(EndpointProperty.Host)}:{SmtpEndpoint.Property(EndpointProperty.Port)}"
);
A assinatura do método Create é a seguinte:
public static ReferenceExpression Create(
in ExpressionInterpolatedStringHandler handler)
Este não é um argumento String regular. O método usa o padrão de manipulador de cadeia de caracteres interpolado, para capturar o modelo de cadeia de caracteres interpolada e os valores referenciados dentro dele para permitir o processamento personalizado. No caso de .NET.NET Aspire, esses detalhes são capturados em um ReferenceExpression que pode ser avaliado à medida que cada valor referenciado na cadeia de caracteres interpolada se torna disponível.
Veja como funciona o fluxo de execução:
- Um recurso que implementa IResourceWithConnectionString é adicionado ao modelo (por exemplo,
AddMailDev(...)
). - O
IResourceBuilder<MailDevResource>
é passado para o WithReference, que possui uma sobrecarga especial para lidar com implementadores de IResourceWithConnectionString. - O
WithReference
encapsula o recurso em uma instância de ConnectionStringReference e o objeto é capturado em um EnvironmentCallbackAnnotation que é avaliado depois que o projeto .NET.NET Aspire é criado e começa a ser executado. - À medida que o processo que faz referência à cadeia de conexão começa .NET.NET Aspire começa a avaliar a expressão. Primeiro, ele obtém o ConnectionStringReference e chama IValueProvider.GetValueAsync.
- O método
GetValueAsync
obtém o valor da propriedade ConnectionStringExpression para obter a instância de ReferenceExpression. - O método IValueProvider.GetValueAsync chama GetValueAsync para processar a cadeia de caracteres interpolada capturada anteriormente.
- Como a cadeia de caracteres interpolada contém referências a outros tipos de referência, como o EndpointReference, eles também são avaliados, e o valor real é substituído (e agora está disponível).
Publicação de manifesto
A interface IManifestExpressionProvider foi projetada para resolver o problema de compartilhamento de informações de conexão entre recursos na implantação. A solução para esse problema específico é descrita na visão geral da rede de loop interno .NET.NET Aspire. Da mesma forma que o desenvolvimento local, muitos dos valores são necessários para configurar o aplicativo, mas eles não podem ser determinados até que o aplicativo esteja sendo implantado por meio de uma ferramenta, como azd
(Azure Developer CLI).
Para resolver esse problema, .NET.NET Aspire produz um arquivo de manifesto que azd
e outras ferramentas de implantação interpretam. Em vez de especificar valores concretos para informações de conexão entre recursos, é usada uma sintaxe de expressão que as ferramentas de implantação avaliam. Geralmente, o arquivo de manifesto não é visível para os desenvolvedores, mas é possível gerar um para inspeção manual. O comando a seguir pode ser usado no host do aplicativo para produzir um manifesto.
dotnet run --project MailDevResource.AppHost/MailDevResource.AppHost.csproj -- --publisher manifest --output-path aspire-manifest.json
Esse comando produz um arquivo de manifesto como o seguinte:
{
"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"
}
}
}
}
}
Como o MailDevResource
implementa a IResourceWithConnectionString, a lógica de publicação do manifesto no .NET.NET Aspire sabe que, embora o MailDevResource
seja um recurso de contêiner, ele também precisa de um campo connectionString
. O campo connectionString
faz referência a outras partes do recurso maildev
no manifesto para produzir a cadeia de caracteres final:
{
// ... other content omitted.
"connectionString": "smtp://{maildev.bindings.smtp.host}:{maildev.bindings.smtp.port}"
}
.NET .NET Aspire sabe como formar essa cadeia de caracteres porque ela examina ConnectionStringExpression e cria a cadeia de caracteres final por meio da interface IManifestExpressionProvider (da mesma forma que a interface IValueProvider é usada).
O MailDevResource
é incluído automaticamente no manifesto porque é derivado de ContainerResource. Os autores de recursos podem optar por suprimir a saída de conteúdo para o manifesto usando o método de extensão ExcludeFromManifest no construtor 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
}
Deve-se considerar cuidadosamente se o recurso deve estar presente no manifesto ou se ele deve ser suprimido. Se o recurso estiver sendo adicionado ao manifesto, ele deverá ser configurado de modo que seja seguro e seguro de usar.
Resumo
No tutorial de recursos personalizados, você aprendeu a criar um recurso de .NET Aspire personalizado que usa um aplicativo contêiner existente (MailDev). Em seguida, você usou isso para melhorar a experiência de desenvolvimento local, facilitando o teste de recursos de email que podem ser usados em um aplicativo. Esses aprendizados podem ser aplicados à criação de outros recursos personalizados que podem ser usados em aplicativos baseados em .NET.NET Aspire. Este exemplo específico não incluiu nenhuma integração personalizada, mas é possível criar integrações personalizadas para facilitar o uso do recurso pelos desenvolvedores. Nesse cenário, você conseguiu contar com a classe SmtpClient
existente na plataforma .NET para enviar emails.