Поделиться через


Создайте пользовательские интеграции размещения .NET.NET Aspire

.NET .NET Aspire улучшает возможности разработки, предоставляя многократно используемые стандартные блоки, которые можно использовать для быстрого упорядочивания зависимостей приложений и предоставления им собственного кода. Одним из ключевых строительных блоков приложения на основе Aspireявляется ресурс . Рассмотрим приведенный ниже код:

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

В приведенном выше коде представлено четыре ресурса:

  1. cache: контейнер Redis.
  2. pgserver: контейнер Postgres.
  3. inventorydb: база данных, размещенная в pgserver.
  4. inventoryservice: приложение ASP.NET Core.

Большинство кода, связанного с .NET.NET Aspire, который пишет средний разработчик, сосредоточено на добавлении ресурсов в модель приложения и создании ссылок между ними.

Ключевые элементы пользовательского ресурса .NET.NET Aspire

Для создания пользовательского ресурса в .NET.NET Aspire требуется следующее:

  1. Настраиваемый тип ресурса, реализующий IResource
  2. Метод расширения для IDistributedApplicationBuilder с именем Add{CustomResource}, где {CustomResource} — имя настраиваемого ресурса.

Когда пользовательскому ресурсу требуется опциональная настройка, разработчики могут реализовать методы расширения с суффиксом , чтобы сделать эти параметры конфигурации обнаруживаемыми, используя шаблон построителя.

Практический пример: MailDev

Чтобы понять, как разрабатывать пользовательские ресурсы, в этой статье показано, как создать пользовательский ресурс для MailDev. MailDev — это средство с открытым исходным кодом, которое предоставляет локальную почту server, предназначенную для тестирования поведения отправки электронной почты в своем приложении. Дополнительные сведения см. в репозитории MailDevGitHub.

В этом примере вы создадите проект .NET Aspire в качестве тестовой среды для создаваемого ресурса MailDev. Хотя вы можете создать пользовательские ресурсы в существующих проектах .NET Aspire, рекомендуется рассмотреть, может ли пользовательский ресурс использоваться в нескольких решениях на основе .NET Aspireи должен быть разработан в качестве многократно используемой интеграции.

Настройка начального проекта

Создайте новый проект .NET.NET Aspire, который используется для тестирования нового ресурса, который мы разрабатываем.

dotnet new aspire -o MailDevResource
cd MailDevResource
dir

После создания проекта отобразится список, содержащий следующее:

  • MailDevResource.AppHost: хост приложения , который используется для тестирования пользовательского ресурса.
  • MailDevResource.ServiceDefaults: служба по умолчанию используется для проекта в проектах, связанных с услугами.
  • MailDevResource.sln: файл решения, ссылающийся на оба проекта.

Убедитесь, что проект может успешно выполнить сборку и запуск, выполнив следующую команду:

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

Выходные данные консоли должны выглядеть примерно так:

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.

Выберите ссылку панели мониторинга в браузере, чтобы просмотреть панель мониторинга .NET.NET Aspire:

Снимок экрана: пустая панель мониторинга .NET.NET Aspire для тестового проекта.

Нажмите клавиши CTRL+C, чтобы завершить работу приложения (вы можете закрыть вкладку браузера).

Создание библиотеки для расширения ресурсов

.NET Aspire ресурсы — это просто классы и методы, содержащиеся в библиотеке классов, которая ссылается на библиотеку хостинга .NET Aspire (Aspire.Hosting). Поместив ресурс в отдельный проект, вы можете легче поделиться им между приложениями, основанными на .NET.NET Aspire, и потенциально упаковать и распространять его через NuGet.

  1. Создайте проект библиотеки классов с именем MailDev. Хостинг.

    dotnet new classlib -o MailDev.Hosting
    
  2. Добавьте Aspire.Hosting в библиотеку классов в качестве ссылки на пакет.

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

    Важный

    Указанная здесь версия должна соответствовать версии установленной .NET.NET Aspire рабочей нагрузки.

  3. Добавьте ссылку на библиотеку классов в проект MailDevResource.AppHost.

    dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
    
  4. Добавьте проект библиотеки классов в файл решения.

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

После выполнения следующих действий можно запустить проект:

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

Это приводит к отображению предупреждения в консоли:

.\.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]

Это связано с тем, что .NET.NET Aspire обрабатывает ссылки на проекты в узле приложения, как если бы они были проектами службы. Чтобы сообщить .NET.NET Aspire, что ссылка на проект должна рассматриваться как неслужбный проект, измените ссылку MailDevResource.AppHostMailDevResource.AppHost.csproj файлов на проект MailDev.Hosting следующим образом:

<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>

Теперь, когда вы запускаете хост приложения, в консоли не отображается предупреждение.

Определение типов ресурсов

В библиотеке классов MailDev.Hosting содержатся тип ресурса и методы расширения для добавления ресурса в хост приложения. Сначала следует подумать об интерфейсе, который вы хотите предоставить разработчикам при использовании пользовательского ресурса. В случае этого настраиваемого ресурса вы будете хотеть, чтобы разработчики могли бы писать код следующим образом:

var builder = DistributedApplication.CreateBuilder(args);

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

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

Для этого требуется настраиваемый ресурс с именем MailDevResource, который реализует IResourceWithConnectionString, чтобы потребители могли использовать его с расширением WithReference для внедрения сведений о подключении для MailDevserver в виде строки подключения.

MailDev доступен как ресурс контейнера, поэтому вы также хотите получить производный от ContainerResource, чтобы мы могли использовать различные предварительно существующие расширения, ориентированные на контейнеры, в .NET.NET Aspire.

Замените содержимое файла Class1.cs в проекте MailDev.Hosting и переименуйте файл в MailDevResource.cs следующим кодом:

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

В предыдущем пользовательском ресурсе EndpointReference и ReferenceExpression являются примерами нескольких типов, реализующих коллекцию интерфейсов, таких как IManifestExpressionProvider, IValueProviderи IValueWithReferences. Для получения дополнительной информации об этих типах и их роли в .NET.NET Aspireсм. в технических сведениях.

Определение расширений ресурсов

Чтобы разработчикам было проще использовать пользовательский ресурс, необходимо добавить в проект MailDev.Hosting метод расширения с именем AddMailDev. Метод расширения AddMailDev отвечает за настройку ресурса, чтобы он был успешно запущен в качестве контейнера.

Добавьте следующий код в новый файл с именем MailDevResourceBuilderExtensions.cs в проект 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";
}

Проверка пользовательской интеграции внутри узла приложения

Теперь, когда базовая структура настраиваемого ресурса завершена, пришло время протестировать его в реальном проекте AppHost. Откройте файл Program.cs в проекте MailDevResource.AppHost и обновите его следующим кодом:

var builder = DistributedApplication.CreateBuilder(args);

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

builder.Build().Run();

После обновления файла Program.cs запустите проект узла приложения и откройте панель мониторинга:

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

Через несколько минут на панели мониторинга показано, что запущен ресурс maildev, и гиперссылка будет доступна, которая перейдет к веб-приложению MailDev, в котором отображается содержимое каждой отправленной вами электронной почты.

Панель мониторинга .NET.NET Aspire должна выглядеть следующим образом:

MailDev ресурс, видимый на панели мониторинга .NET Aspire.

веб-приложение MailDev должно выглядеть следующим образом:

MailDev веб-интерфейс, работающий в качестве контейнера, управляемого .NET Aspire.

Добавьте проект службы .NET в хост приложения для тестирования

После того как .NET Aspire успешно запустит интеграцию MailDev, следует воспользоваться сведениями о подключении для MailDev в проекте .NET. В .NET.NET Aspire обычно существует пакет размещения и один или несколько пакетов компонентов . Например, рассмотрим:

  • Пакет размещения: используется для представления ресурсов в приложенческой модели.
    • Aspire.Hosting.Redis
  • Пакеты компонентов: предназначены для настройки и использования библиотек client.
    • Aspire.StackExchange.Redis
    • Aspire.StackExchange.Redis.DistributedCaching
    • Aspire.StackExchange.Redis.OutputCaching

В случае ресурса MailDev платформа .NET уже имеет простую client протокола SMTP в виде SmtpClient. В этом примере этот существующий API используется для простоты, хотя другие типы ресурсов могут воспользоваться пользовательскими библиотеками интеграции, чтобы помочь разработчикам.

Чтобы протестировать комплексный сценарий, вам потребуется проект .NET, в который можно внедрить сведения о подключении для ресурса MailDev. Добавьте проект веб-API:

  1. Создайте проект .NET с именем MailDevResource.NewsletterService.

    dotnet new webapi --use-minimal-apis -o MailDevResource.NewsletterService
    
  2. Добавьте ссылку на проект MailDev.Hosting.

    dotnet add ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj reference ./MailDev.Hosting/MailDev.Hosting.csproj
    
  3. Добавьте ссылку на проект MailDevResource.AppHost.

    dotnet add ./MailDevResource.AppHost/MailDevResource.AppHost.csproj reference ./MailDevResource.NewsletterService/MailDevResource.NewsletterService.csproj
    
  4. Добавьте новый проект в файл решения.

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

После добавления проекта и обновления ссылок откройте Program.cs проекта MailDevResource.AppHost.csproj и обновите исходный файл следующим образом:

var builder = DistributedApplication.CreateBuilder(args);

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

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

builder.Build().Run();

После обновления файла Program.cs запустите хост приложения еще раз. Затем убедитесь, что служба бюллетеня запущена и что переменная среды ConnectionStrings__maildev была добавлена в процесс. На странице "Ресурсы" найдите строку newsletterservice и выберите ссылку "Посмотреть" в столбце "Детали".

переменные среды для службы информационных бюллетеней на панели мониторинга .NET.NET Aspire.

На предыдущем снимку экрана показаны переменные среды для проекта newsletterservice. Переменная среды ConnectionStrings__maildev — это строка подключения, внедренная в проект ресурсом maildev.

Использование строки подключения для отправки сообщений

Чтобы использовать сведения о подключении SMTP, которые были внедрены в проект службы бюллетеня, вы инжектируете экземпляр SmtpClient в контейнер внедрения зависимостей в качестве singleton. Добавьте следующий код в файл Program.cs в проекте MailDevResource.NewsletterService, чтобы настроить службу singleton. В классе Program сразу после комментария // 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;
});

Кончик

Этот фрагмент кода зависит от официального SmtpClient, однако; этот тип устарел на некоторых платформах и не рекомендуется для других. Более современный подход с помощью MailKitсм. в статье Создание пользовательских интеграции .NET Aspireclient.

Чтобы протестировать client, добавьте два простых метода subscribe и unsubscribe POST в сервис рассылки. Чтобы настроить маршруты ASP.NET Core, добавьте следующий код, заменив вызов MapGet weatherforecast в файле Program.cs проекта MailDevResource.NewsletterService.

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

Совет

Не забудьте ссылаться на пространства имен System.Net.Mail и Microsoft.AspNetCore.Mvc в Program.cs, если редактор кода не добавляет их автоматически.

После обновления файла Program.cs запустите хост приложения и используйте браузер или curl, чтобы обратиться по следующим URL-адресам (если вы используете Visual Studio, вы можете использовать файлы .http).

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

Для использования этого API можно использовать curl для отправки запроса. Следующая команда curl отправляет HTTP-запрос POST к конечной точке subscribe, и она ожидает значение параметра запроса email для подписки на информационный бюллетень. Заголовок Content-Type установлен в application/json, чтобы указать, что тело запроса находится в формате JSON.

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

Следующий API — это конечная точка unsubscribe. Эта конечная точка используется для отмены подписки на информационный бюллетень.

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

Чтобы отменить подписку из бюллетеня, можно использовать следующую команду curl, передав параметр email в конечную точку unsubscribe в виде строки запроса:

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

Совет

Замените https://localhost:7251 правильным портом localhost (URL-адрес запущенного узла приложения).

Если эти вызовы API возвращают успешный ответ (HTTP 200, ОК), вы сможете выбрать на ресурсе maildev панель мониторинга, а MailDev UI отобразит сообщения электронной почты, отправленные в конечную точку SMTP.

сообщения электронной почты, отображаемые в MailDev пользовательском интерфейсе

Технические сведения

В следующих разделах рассматриваются различные технические сведения, которые важны для разработки пользовательских ресурсов для .NET.NET Aspire.

Безопасная сеть

В этом примере ресурс MailDev — это ресурс контейнера, который предоставляется хост-компьютеру по протоколу HTTP и SMTP. Ресурс MailDev — это средство разработки и не предназначено для использования в рабочей среде. Чтобы вместо этого использовать ПРОТОКОЛ HTTPS, см. раздел MailDev: настройка HTTPS.

При разработке пользовательских ресурсов, которые предоставляют конечные точки сети, важно учитывать вопросы безопасности ресурса. Например, если ресурс является базой данных, важно убедиться, что база данных безопасна и что строка подключения не предоставляется общедоступному Интернету.

Тип ReferenceExpression и EndpointReference

В приведенном выше коде MailDevResource имеет два свойства:

Эти типы используются в .NET Aspire для представления данных конфигурации, которые не завершаются до тех пор, пока проект .NET Aspire не будет запущен или опубликован в облаке с помощью средства, например Azure Developer CLI (azd).

Основная проблема заключается в том, что эти типы помогают отложить разрешение конкретных сведений о конфигурации до тех пор, пока вся информация не станет доступной.

Например, MailDevResource предоставляет свойство с именем ConnectionStringExpression в соответствии с требованиями интерфейса IResourceWithConnectionString. Тип свойства ReferenceExpression и создается путем передачи интерполированной строки методу Create.

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

Подпись для метода Create выглядит следующим образом:

public static ReferenceExpression Create(
    in ExpressionInterpolatedStringHandler handler)

Это не обычный аргумент String. Метод использует шаблон интерполированного обработчика строк для записи интерполированного шаблона строки и значений, на которые он ссылается, чтобы обеспечить пользовательскую обработку. В случае .NET.NET Aspireэти сведения записываются в ReferenceExpression, которые можно оценить по мере того, как каждое значение, на которое ссылается интерполированная строка, становится доступной.

Вот как работает поток выполнения:

  1. Ресурс, реализующий IResourceWithConnectionString, добавляется в модель (например, AddMailDev(...)).
  2. IResourceBuilder<MailDevResource> передается в WithReference, которая имеет специальную перегрузку для обработки реализаторов IResourceWithConnectionString.
  3. WithReference упаковывает ресурс в экземпляр ConnectionStringReference, и объект помещается в EnvironmentCallbackAnnotation, который вычисляется после того, как проект .NET.NET Aspire будет создан и начнёт выполняться.
  4. Когда процесс, ссылающийся на строку подключения, запускается, .NET.NET Aspire начинает вычислять выражение. Сначала он получает ConnectionStringReference и вызывает IValueProvider.GetValueAsync.
  5. Метод GetValueAsync получает значение свойства ConnectionStringExpression для получения экземпляра ReferenceExpression.
  6. Затем метод IValueProvider.GetValueAsync вызывает GetValueAsync для обработки ранее захваченной интерполированной строки.
  7. Так как интерполированная строка содержит ссылки на другие ссылочные типы, такие как EndpointReference они также вычисляются и заменяются реальным значением (которое в настоящее время доступно).

Публикация манифеста

Интерфейс IManifestExpressionProvider предназначен для решения проблемы совместного использования сведений о подключении между ресурсами во время развертывания. Решение данной проблемы подробно описано в обзоре сети "внутреннего цикла" .NET.NET Aspire. Аналогично локальной разработке, многие из значений необходимы для настройки приложения, но они не могут быть определены, пока приложение не будет развернуто с помощью средства, например azd (Azure Developer CLI).

Чтобы решить эту проблему, .NET.NET Aspire создает файл манифеста, который azd и другие средства развертывания интерпретируют. Вместо указания конкретных значений для сведений о подключении между ресурсами используется синтаксис выражений, которые вычисляются средствами развертывания. Как правило, файл манифеста не отображается разработчикам, но его можно создать для ручной проверки. Приведенная ниже команда может использоваться на узле приложения для создания манифеста.

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

Эта команда создает файл манифеста, как показано ниже:

{
  "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"
        }
      }
    }
  }
}

Так как MailDevResource реализует IResourceWithConnectionString логику публикации манифеста в .NET.NET Aspire знает, что, хотя MailDevResource является ресурсом контейнера, он также нуждается в поле connectionString. Поле connectionString ссылается на другие части ресурса maildev в манифесте, чтобы создать окончательную строку:

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

.NET .NET Aspire знает, как сформировать эту строку, так как она смотрит на ConnectionStringExpression и создает окончательную строку через интерфейс IManifestExpressionProvider (так же, как используется интерфейс IValueProvider).

MailDevResource автоматически включается в манифест, так как он является производным от ContainerResource. Авторы ресурсов могут отключить вывод содержимого манифеста с помощью метода расширения ExcludeFromManifest в построителе ресурсов.

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
}

Следует внимательно учитывать, должен ли ресурс присутствовать в манифесте или следует ли его подавлять. Если ресурс добавляется в манифест, его следует настроить таким образом, чтобы он был безопасным и безопасным для использования.

Сводка

В руководстве по пользовательским ресурсам вы узнали, как создать пользовательский .NET Aspire ресурс, использующий существующее контейнерное приложение (MailDev). Затем вы использовали это для улучшения локального интерфейса разработки, упрощая тестирование возможностей электронной почты, которые могут использоваться в приложении. Эти выводы можно применять к созданию других пользовательских ресурсов, которые можно использовать в приложениях на основе .NET.NET Aspire. Этот конкретный пример не включал пользовательские интеграции, но можно создать пользовательские интеграции, чтобы упростить использование ресурсов разработчиками. В этом сценарии вы могли полагаться на существующий класс SmtpClient на платформе .NET для отправки сообщений электронной почты.

Дальнейшие действия