Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tento článek je pokračováním dvou předchozích článků, které demonstrují vytváření vlastních hostitelských integrací a integrací vlastních klientů .
Jednou z hlavních výhod .NET.NET Aspire je to, jak zjednodušuje konfiguraci prostředků a využívání klientů (nebo integrací). Tento článek demonstruje, jak sdílet přihlašovací údaje pro ověřování z vlastního prostředku v integračním řešení hostování, k využívajícímu klientovi v rámci vlastní integrace klienta. Vlastní prostředek je kontejner MailDev, který podporuje použití buď příchozích, nebo odchozích přihlašovacích údajů. Vlastní integrace klienta je klient MailKit, který odesílá e-maily.
Požadavky
Vzhledem k tomu, že tento článek pokračuje od předchozího obsahu, měli byste už vytvořit výsledné řešení jako výchozí bod pro tento článek. Pokud jste to ještě neudělali, vyplňte následující články:
- Vytvoření vlastních .NET.NET Aspire integrací hostování
- Vytvoření vlastních integrací klientů .NET.NET Aspire
Výsledné řešení z těchto předchozích článků obsahuje následující projekty:
- MailDev. Hostování: Obsahuje vlastní typ prostředku pro kontejner MailDev.
MailDevResource.AppHost : Hostitel aplikace, který používá vlastní prostředek a definuje ho jako závislost pro službu newsletteru. - MailDevResource.NewsletterService: Projekt webového rozhraní API ASP.NET Core, který odesílá e-maily pomocí kontejneru MailDev.
- MailDevResource.ServiceDefaults: Obsahuje výchozí konfigurace služby, které jsou určeny ke sdílení.
-
MailKit.Client: Obsahuje vlastní integraci klienta, která zpřístupňuje sadu MailKit
SmtpClient
prostřednictvím továrny.
Aktualizace prostředku MailDev
Pokud chcete tok přihlašovacích údajů pro ověřování z prostředku MailDev do integrace MailKitu, musíte aktualizovat prostředek MailDev tak, aby zahrnoval parametry uživatelského jména a hesla.
Kontejner MailDev podporuje základní ověřování pro příchozí i odchozí protokol SMTP (Simple Mail Transfer Protocol). Pokud chcete nakonfigurovat přihlašovací údaje pro příchozí, musíte nastavit MAILDEV_INCOMING_USER
a MAILDEV_INCOMING_PASS
proměnných prostředí. Pro více informací si přečtěte téma MailDev: Použití. Aktualizujte soubor MailDevResource.cs v projektu MailDev.Hosting
nahrazením jeho obsahu následujícím kódem jazyka C#:
// 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,
ParameterResource? username,
ParameterResource password)
: ContainerResource(name), IResourceWithConnectionString
{
// Constants used to refer to well known-endpoint names, this is specific
// for each resource type. MailDev exposes an SMTP and HTTP endpoints.
internal const string SmtpEndpointName = "smtp";
internal const string HttpEndpointName = "http";
private const string DefaultUsername = "mail-dev";
// 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;
/// <summary>
/// Gets the parameter that contains the MailDev SMTP server username.
/// </summary>
public ParameterResource? UsernameParameter { get; } = username;
internal ReferenceExpression UserNameReference =>
UsernameParameter is not null ?
ReferenceExpression.Create($"{UsernameParameter}") :
ReferenceExpression.Create($"{DefaultUsername}");
/// <summary>
/// Gets the parameter that contains the MailDev SMTP server password.
/// </summary>
public ParameterResource PasswordParameter { get; } = password;
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(
$"Endpoint=smtp://{SmtpEndpoint.Property(EndpointProperty.HostAndPort))};Username={UserNameReference};Password={PasswordParameter}"
);
}
Tyto aktualizace přidávají vlastnost UsernameParameter
a PasswordParameter
. Tyto vlastnosti slouží k uložení parametrů pro MailDev uživatelské jméno a heslo. Vlastnost ConnectionStringExpression
se aktualizuje tak, aby zahrnovala parametry uživatelského jména a hesla do připojovacího řetězce. Dále aktualizujte soubor MailDevResourceBuilderExtensions.cs v projektu MailDev.Hosting
následujícím kódem jazyka C#:
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
{
private const string UserEnvVarName = "MAILDEV_INCOMING_USER";
private const string PasswordEnvVarName = "MAILDEV_INCOMING_PASS";
/// <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,
IResourceBuilder<ParameterResource>? userName = null,
IResourceBuilder<ParameterResource>? password = null)
{
var passwordParameter = password?.Resource ??
ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(
builder, $"{name}-password");
// 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, userName?.Resource, passwordParameter);
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)
.WithEnvironment(context =>
{
context.EnvironmentVariables[UserEnvVarName] = resource.UserNameReference;
context.EnvironmentVariables[PasswordEnvVarName] = resource.PasswordParameter;
});
}
}
// 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";
}
Předchozí kód aktualizuje metodu rozšíření AddMailDev
tak, aby zahrnovala parametry userName
a password
. Metoda WithEnvironment
se aktualizuje tak, aby zahrnovala proměnné prostředí UserEnvVarName
a PasswordEnvVarName
. Tyto proměnné prostředí se používají k nastavení MailDev uživatelského jména a hesla.
Aktualizace hostitele aplikace
Teď, když je prostředek aktualizovaný tak, aby zahrnoval parametry uživatelského jména a hesla, musíte aktualizovat hostitele aplikace tak, aby tyto parametry zahrnoval. Aktualizujte soubor Program.cs v projektu MailDevResource.AppHost
následujícím kódem jazyka C#:
var builder = DistributedApplication.CreateBuilder(args);
var mailDevUsername = builder.AddParameter("maildev-username");
var mailDevPassword = builder.AddParameter("maildev-password");
var maildev = builder.AddMailDev(
name: "maildev",
userName: mailDevUsername,
password: mailDevPassword);
builder.AddProject<Projects.MailDevResource_NewsletterService>("newsletterservice")
.WithReference(maildev);
builder.Build().Run();
Předchozí kód přidá dva parametry pro MailDev uživatelské jméno a heslo. Tyto parametry přiřadí MAILDEV_INCOMING_USER
a MAILDEV_INCOMING_PASS
proměnným prostředí. Metoda AddMailDev
má dvě zřetězená volání WithEnvironment
, která zahrnují tyto proměnné prostředí. Další informace o parametrech naleznete v tématu Externí parametry.
Dále nakonfigurujte tajné kódy pro tyto parametry. Klikněte pravým tlačítkem na projekt MailDevResource.AppHost
a vyberte Manage User Secrets
. Do souboru JSON přidejte následující :
{
"Parameters:maildev-username": "@admin",
"Parameters:maildev-password": "t3st1ng"
}
Varování
Tyto přihlašovací údaje slouží jenom pro demonstrační účely a MailDev je určená pro místní vývoj. Tyto přihlašovací údaje jsou fiktivní a neměly by se používat v produkčním prostředí.
Aktualizujte integraci MailKit
Je vhodné, aby integrace klientů očekávaly, že připojovací řetězce budou obsahovat různé páry klíč/hodnota a parsovat tyto páry do příslušných vlastností. Aktualizujte soubor MailKitClientSettings.cs v projektu MailKit.Client
následujícím kódem jazyka C#:
using System.Data.Common;
using System.Net;
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 the network credentials that are optionally configurable for SMTP
/// server's that require authentication.
/// </summary>
/// <value>
/// The default value is <see langword="null"/>.
/// </value>
public NetworkCredential? Credentials { 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;
if (builder.TryGetValue("Username", out var username) &&
builder.TryGetValue("Password", out var password))
{
Credentials = new(
username.ToString(), password.ToString());
}
}
}
}
Předchozí třída nastavení nyní obsahuje vlastnost Credentials
typu NetworkCredential
. Metoda ParseConnectionString
je aktualizována pro parsování klíčů Username
a Password
z připojovacího řetězce. Pokud jsou k dispozici klíče Username
a Password
, vytvoří se NetworkCredential
a přiřadí se k Credentials
vlastnosti.
Jakmile je třída nastavení aktualizována tak, aby rozuměla přihlašovacím údajům a používala je, aktualizujte továrnu, aby podmíněně používala tyto přihlašovací údaje, pokud jsou nakonfigurované. Aktualizujte soubor MailKitClientFactory.cs v projektu MailKit.Client
následujícím kódem jazyka C#:
using System.Net;
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);
if (settings.Credentials is not null)
{
await _client.AuthenticateAsync(settings.Credentials, cancellationToken)
.ConfigureAwait(false);
}
}
}
finally
{
_semaphore.Release();
}
return _client;
}
public void Dispose()
{
_client?.Dispose();
_semaphore.Dispose();
}
}
Když továrna zjistí, že jsou přihlašovací údaje nakonfigurovány, ověří se serverem SMTP po připojení a teprve potom vrátí SmtpClient
.
Spusťte ukázku
Teď, když jste aktualizovali prostředek, odpovídající projekty integrace a hostitele aplikace, jste připraveni spustit ukázkovou aplikaci. Pokud chcete spustit ukázku z integrovaného vývojového prostředí, vyberte F5 nebo spusťte aplikaci pomocí dotnet run
z kořenového adresáře řešení. Měli byste vidět řídicí panel .NET.NET Aspire. Přejděte ke kontejnerovému prostředku maildev
a prohlédněte si podrobnosti. Parametry uživatelského jména a hesla byste měli vidět v podrobnostech o prostředku v části Proměnné prostředí:
Stejně tak byste měli v podrobnostech o prostředku newsletterservice
vidět připojovací řetězec v části Proměnné prostředí:
Ověřte, že všechno funguje podle očekávání.
Shrnutí
Tento článek ukazuje, jak přenášet přihlašovací údaje pro ověřování z vlastního prostředku do vlastní klientské integrace. Vlastní prostředek je kontejner MailDev, který podporuje použití buď příchozích, nebo odchozích přihlašovacích údajů. Vlastní integrace klienta je klient MailKit, který odesílá e-maily. Aktualizací prostředku tak, aby zahrnoval parametry username
a password
, a aktualizací integrace pro správné zpracování a použití těchto parametrů, ověřovací toky předávají přihlašovací údaje z integrace hostování do integrace klienta.