交互服务(预览版)

使用交互服务(Aspire.Hosting.IInteractionService)可以提示用户输入、请求确认和显示消息。 交互服务在两个不同的上下文中工作:

  • Aspire 仪表板:直接运行 aspire run 或启动 AppHost 时,交互在仪表板 UI 中显示为对话框和通知。
  • Aspire CLI:在运行 aspire publishaspire deploy通过命令行接口提示交互时。

这对于需要从用户收集信息或提供有关作状态的反馈(无论应用程序是如何启动或部署的)的情况都很有用的。

IInteractionService API 接口

IInteractionService 依赖项注入容器检索 DistributedApplication 接口。 IInteractionService 可以注入到从 DI 创建或解析 IServiceProvider的类型中,该类型通常在传递给事件的上下文参数上可用。

请求 IInteractionService时,请务必检查它是否可供使用。 如果在不可用(IInteractionService.IsAvailable 返回 false)时尝试使用交互服务,则会引发异常。

var interactionService = serviceProvider.GetRequiredService<IInteractionService>();
if (interactionService.IsAvailable)
{
    var result = await interactionService.PromptConfirmationAsync(
        title: "Delete confirmation",
        message: "Are you sure you want to delete the data?");
        
    if (result.Data)
    {
        // Run your resource/command logic.
    }
}

交互服务有多种方法可用于与用户交互或显示消息。 这些方法的行为取决于执行上下文:

  • 仪表板上下文aspire run或直接启动 AppHost):交互在仪表板 Web 界面中Aspire显示为模式对话、通知和表单输入。
  • CLI 上下文aspire publishaspire deploy):通过命令行界面进行交互,使用基于文本的提示和响应。

以下部分介绍如何在这两个上下文中有效地使用这些 API:

Method Description 支持的上下文
PromptMessageBoxAsync 显示一个模式对话框,其中包含用于用户交互的消息和按钮。 仅限于仪表板
PromptNotificationAsync 将仪表板中的非模式通知显示为消息栏。 仅限于仪表板
PromptConfirmationAsync 显示一个确认对话框,其中包含用于用户确认或取消作的选项。 仅限于仪表板
PromptInputAsync 提示用户输入单个输入值,例如文本或机密。 仪表板、CLI (命令行界面)
PromptInputsAsync 在单一对话框(仪表板)或按顺序(CLI)提示用户输入多个值。 仪表板、CLI (命令行界面)

Important

aspire publishaspire deploy 操作期间,仅 PromptInputAsyncPromptInputsAsync 可用。 如果在 CLI 上下文中调用其他交互方法(PromptMessageBoxAsyncPromptNotificationAsyncPromptConfirmationAsync)将引发异常。

使用交互服务的位置

任何可用的基于回调的 IResourceBuilder<T> 扩展方法都可以使用交互服务来提示用户输入或确认。 在这些方案中使用交互服务:

  • 自定义资源类型:从用户收集输入,或在创建自定义资源类型时确认操作。

    资源类型可以自由定义仪表板交互,例如提示用户输入或显示消息。 借助交互服务,可以在用户管理仪表板或 CLI 中的 Aspire 资源时为用户创建更交互式的体验。 有关详细信息,请参阅 创建自定义 Aspire 托管集成

  • 自定义资源命令:将命令添加到仪表板或 CLI 中的 Aspire 资源。 使用这些交互服务在运行这些命令时提示用户输入或确认。

    当将调用WithCommand链接到目标IResourceBuilder<T>时,例如,可以通过回调使用交互服务来收集输入或确认操作。 有关详细信息,请参阅中的Aspire自定义资源命令

  • 发布和部署工作流:在 aspire publishaspire deploy 操作期间,使用交互服务收集特定于部署的配置,并通过 CLI 确认破坏性操作。

这些方法可帮助你创建本地开发、仪表板交互和部署工作流的交互式用户友好体验。

Important

本文演示了在WithCommand回调和FakeResource类型的上下文中使用的交互服务。同样的原则也适用于支持用户交互的其他扩展方法。

例如:

var builder = DistributedApplication.CreateBuilder(args);

builder.AddFakeResource("fake-resource")
       .WithCommand("msg-dialog", "Example Message Dialog", async context =>
{
    var interactionService = context.ServiceProvider.GetRequiredService<IInteractionService>();
    
    // Use interaction service...

    return CommandResults.Success();
});

对于 CLI 特定的上下文,交互服务将根据所执行的操作从PublishingContextDeploymentContext中检索。

显示消息

可通过多种方式向用户显示消息:

  • 对话框消息:在对话框中显示重要信息。
  • 通知消息:在通知中显示不太重要的信息。

Note

消息显示方法(PromptMessageBoxAsyncPromptNotificationAsync)仅在仪表板上下文中可用。 如果在 aspire publishaspire deploy 操作期间调用,这些方法将引发异常。

显示消息对话框

对话消息提供需要用户注意的重要信息。

该方法 IInteractionService.PromptMessageBoxAsync 显示具有可自定义响应选项的消息。

var interactionService = context.ServiceProvider.GetRequiredService<IInteractionService>();

var result = await interactionService.PromptMessageBoxAsync(
    "Simple Message Box: Example",
    """
    ##### 🤓 Nice!

    It's worth noting that **Markdown** is _supported_
    (and demonstrated here) in the message body. Simply
    configure the options as:

    ```csharp
    var options = new MessageBoxInteractionOptions
    {
        EnableMessageMarkdown = true,
        // Other options...
    };
    ```

    Cool, [📖 learn more](https://free.blessedness.top/dotnet/aspire/extensibility/interaction-service)...
    """,
    new MessageBoxInteractionOptions
    {
        EnableMessageMarkdown = true,
        PrimaryButtonText = "Awesome"
    }
);

if (result.Canceled)
{
    return CommandResults.Failure("User cancelled.");
}

return result.Data
    ? CommandResults.Success()
    : CommandResults.Failure("The user doesn't like the example");

仪表板视图:

Aspire 仪表板界面显示带有标题、消息和按钮的消息对话框。

CLI 视图:

该方法 PromptMessageBoxAsync 仅适用于仪表板上下文。 如果在aspire publishaspire deploy期间调用它,该方法将引发异常,并且不会在 CLI 中显示消息。

显示通知消息

通知消息提供非模态通知。

Tip

在仪表板中,通知消息显示在顶部,因此可以一次显示多条消息。 可以通过等待每条通知被关闭后再展示下一个,依次显示通知。 或者,您可以同时显示多个通知,而无需等待每个通知被关闭。

IInteractionService.PromptNotificationAsync(String, String, NotificationInteractionOptions, CancellationToken)方法在仪表板上下文中显示包含可选操作链接的信息性消息。 如果不需要,则无需等待通知消息的结果。 这对于通知特别有用,因为你可能想要显示通知并继续,而无需等待用户将其消除。

var interactionService = context.ServiceProvider.GetRequiredService<IInteractionService>();

// Demonstrating various notification types with different intents
var tasks = new List<Task>
{
    interactionService.PromptNotificationAsync(
        title: "Confirmation",
        message: "Are you sure you want to proceed?",
        options: new NotificationInteractionOptions
        {
            Intent = MessageIntent.Confirmation
        }),
    interactionService.PromptNotificationAsync(
        title: "Success",
        message: "Your operation completed successfully.",
        options: new NotificationInteractionOptions
        {
            Intent = MessageIntent.Success,
            LinkText = "View Details",
            LinkUrl = "https://free.blessedness.top/dotnet/aspire/success"
        }),
    interactionService.PromptNotificationAsync(
        title: "Warning",
        message: "Your SSL certificate will expire soon.",
        options: new NotificationInteractionOptions
        {
            Intent = MessageIntent.Warning,
            LinkText = "Renew Certificate",
            LinkUrl = "https://portal.azure.com/certificates"
        }),
    interactionService.PromptNotificationAsync(
        title: "Information",
        message: "There is an update available for your application.",
        options: new NotificationInteractionOptions
        {
            Intent = MessageIntent.Information,
            LinkText = "Update Now",
            LinkUrl = "https://free.blessedness.top/dotnet/aspire"
        }),
    interactionService.PromptNotificationAsync(
        title: "Error",
        message: "An error occurred while processing your request.",
        options: new NotificationInteractionOptions
        {
            Intent = MessageIntent.Error,
            LinkText = "Troubleshoot",
            LinkUrl = "https://free.blessedness.top/dotnet/aspire/troubleshoot"
        })
};

await Task.WhenAll(tasks);

return CommandResults.Success();

前面的示例演示了几种使用通知 API 的方法。 每个方法都显示不同类型的通知,所有这些通知都是并行调用的,并在同一时间显示在仪表板中。

仪表板视图:

Aspire 仪表板界面显示堆叠在页面顶部附近的多个通知消息。显示五个通知,每个通知都有不同类型的通知。

CLI 视图:

该方法 PromptNotificationAsync 在 CLI 上下文中不可用。 如果在aspire publishaspire deploy期间调用它,会引发异常。

提示用户确认

如果需要用户在继续操作之前确认动作,请使用交互服务。 该方法 IInteractionService.PromptConfirmationAsync(String, String, MessageBoxInteractionOptions, CancellationToken) 在仪表板上下文中显示确认提示。 确认提示对于具有重大后果的破坏性操作或行为至关重要。 它们有助于防止意外作,并为用户提供重新考虑其决策的机会。

在进行破坏性操作之前提示确认

对于无法撤消的操作(例如资源删除),请始终提示确认:

var interactionService = context.ServiceProvider.GetRequiredService<IInteractionService>();        

// Prompt for confirmation before resetting database
var resetConfirmation = await interactionService.PromptConfirmationAsync(
    title: "Confirm Reset",
    message: "Are you sure you want to reset the `development-database`? This action **cannot** be undone.",
    options: new MessageBoxInteractionOptions
    {
        Intent = MessageIntent.Confirmation,
        PrimaryButtonText = "Reset",
        SecondaryButtonText = "Cancel",
        ShowSecondaryButton = true,
        EnableMessageMarkdown = true
    });

if (resetConfirmation.Data is true)
{
    // Perform the reset operation...

    return CommandResults.Success();
}
else
{
    return CommandResults.Failure("Database reset canceled by user.");
}

仪表板视图:

Aspire 仪表板界面显示一个确认对话框,其中包含用于确认或取消作的标题、消息和按钮。

CLI 视图:

该方法 PromptConfirmationAsync 在 CLI 上下文中不可用。 如果在aspire publishaspire deploy期间调用它,该方法将引发异常。

用户输入提示

通过交互服务 API,你可以以各种方式提示用户输入。 可以收集单个值或多个值,并支持不同的输入类型,包括文本、机密、选项、布尔值和数字。 演示文稿自动适应执行上下文。

类型 Dashboard CLI 提示
Text Textbox 文本提示
SecretText 带有屏蔽输入的文本框 掩码文本提示
Choice 下拉选项框 选项提示
Boolean Checkbox 布尔选择提示
Number 数字文本框 文本提示

提示用户输入值

可以使用该方法提示输入单个值 IInteractionService.PromptInputAsync ,或者使用 IInteractionService.PromptInputsAsync此方法收集多个信息片段。 在仪表板中,多个输入一起显示在单个对话框中。 在 CLI 中,请求每个输入项一个接一个。

Important

可以使用交互服务创建类似于向导的流程。 通过将多个提示链接在一起(在移动到下一个提示之前处理结果),可以指导用户完成一系列相关问题,以便更轻松地收集所有必要的信息。

请考虑以下示例,这会提示用户输入多个输入值:

var interactionService = context.ServiceProvider.GetRequiredService<IInteractionService>();
var loggerService = context.ServiceProvider.GetRequiredService<ResourceLoggerService>();
var logger = loggerService.GetLogger(fakeResource);

var inputs = new List<InteractionInput>
{
    new()
    {
        Name = "Application Name",
        InputType = InputType.Text,
        Required = true,
        Placeholder = "my-app"
    },
    new()
    {
        Name = "Environment",
        InputType = InputType.Choice,
        Required = true,
        Options =
        [
            new("dev", "Development"),
            new("staging", "Staging"),
            new("test", "Testing")
        ]
    },
    new()
    {
        Name = "Instance Count",
        InputType = InputType.Number,
        Required = true,
        Placeholder = "1"
    },
    new()
    {
        Name = "Enable Monitoring",
        InputType = InputType.Boolean,
        Required = false
    }
};

var appConfigurationInput = await interactionService.PromptInputsAsync(
    title: "Application Configuration",
    message: "Configure your application deployment settings:",
    inputs: inputs);

if (!appConfigurationInput.Canceled)
{
    // Process the collected input values
    var appName = appConfigurationInput.Data[0].Value;
    var environment = appConfigurationInput.Data[1].Value;
    var instanceCount = int.Parse(appConfigurationInput.Data[2].Value ?? "1");
    var enableMonitoring = bool.Parse(appConfigurationInput.Data[3].Value ?? "false");

    logger.LogInformation("""
        Application Name: {AppName}
        Environment: {Environment}
        Instance Count: {InstanceCount}
        Monitoring Enabled: {EnableMonitoring}
        """,
        appName, environment, instanceCount, enableMonitoring);

    // Use the collected values as needed
    return CommandResults.Success();
}
else
{
    return CommandResults.Failure("User canceled application configuration input.");
}

仪表板视图:

这会在仪表板上呈现,如下图所示:

Aspire 显示多个输入对话框的仪表板界面,其中包含用于确认或取消输入的标签、输入字段和按钮。

假设使用以下值填写对话框:

Aspire 仪表板界面显示一个包含填充输入字段和按钮的多个输入对话框,用于确认或取消输入。

选择“ 确定 ”按钮后,资源日志将显示以下输出:

Aspire 仪表板界面显示日志,其中包含在多个输入对话框中输入的输入值。

CLI 视图:

在 CLI 上下文中,按顺序请求相同的输入:

aspire deploy

Step 1: Analyzing model.

       ✓ DONE: Analyzing the distributed application model for publishing and deployment capabilities. 00:00:00
           Found 1 resources that support deployment. (FakeResource)

✅ COMPLETED: Analyzing model. completed successfully

═══════════════════════════════════════════════════════════════════════════════════════════════════════════════

Configure your application deployment settings:
Application Name: example-app
Environment:  Staging
Instance Count: 3
Enable Monitoring: [y/n] (n): y
✓ DEPLOY COMPLETED: Deploying completed successfully

CLI 可能会显示其他提示,具体取决于输入类型。 例如,Enable Monitoring 输入是布尔值选择,因此命令行界面 (CLI) 会提示输入是/否响应。 如果输入 y,则启用监视;如果输入 n,则会禁用监视。 对于环境输入,CLI 会显示可供选择的可用环境列表:

Configure your application deployment settings:
Application Name: example-app
Environment:

> Development
  Staging
  Testing

(Type to search)

输入验证

通过配置InteractionInput可用基本输入验证。 它提供了用于要求TextSecretText字段的值或最大文本长度的选项。

对于复杂方案,可以使用属性 InputsDialogInteractionOptions.ValidationCallback 提供自定义验证逻辑:

// Multiple inputs with custom validation
var databaseInputs = new List<InteractionInput>
{
    new()
    {
        Name = "Database Name",
        InputType = InputType.Text,
        Required = true,
        Placeholder = "myapp-db"
    },
    new()
    {
        Name = "Username",
        InputType = InputType.Text,
        Required = true,
        Placeholder = "admin"
    },
    new()
    {
        Name = "Password",
        InputType = InputType.SecretText,
        Required = true,
        Placeholder = "Enter a strong password"
    },
    new()
    {
        Name = "Confirm password",
        InputType = InputType.SecretText,
        Required = true,
        Placeholder = "Confirm your password"
    }
};

var validationOptions = new InputsDialogInteractionOptions
{
    ValidationCallback = async context =>
    {
        var passwordInput = context.Inputs.FirstOrDefault(i => i.Label == "Password");
        var confirmPasswordInput = context.Inputs.FirstOrDefault(i => i.Label == "Confirm password");

        // Validate password strength
        if (passwordInput?.Value is { Length: < 8 })
        {
            context.AddValidationError(passwordInput, "Password must be at least 8 characters long");
        }

        // Validate password confirmation
        if (passwordInput?.Value != confirmPasswordInput?.Value)
        {
            context.AddValidationError(confirmPasswordInput!, "Passwords do not match");
        }

        await Task.CompletedTask;
    }
};

var dbResult = await interactionService.PromptInputsAsync(
    title: "Database configuration",
    message: "Configure your PostgreSQL database connection:",
    inputs: databaseInputs,
    options: validationOptions);

if (!dbResult.Canceled && dbResult.Data != null)
{
    // Use the validated configuration
}

提示用户输入密码并确认其匹配称为“双重独立验证”输入。 在希望确保用户输入相同密码两次以避免拼写错误或不匹配的情况下,此方法很常见。

用户输入的最佳做法

在提示用户输入时,请考虑以下最佳做法:

  1. 组相关输入:使用多个输入提示收集相关的配置值。 在仪表板中,这些内容显示在单个对话框中;在 CLI 中,会按顺序请求它们,但从概念上进行分组。
  2. 提供明确的标签和占位符:帮助用户了解预期信息,而不考虑上下文。
  3. 使用适当的输入类型:为要收集的数据选择正确的输入类型(密码机密、预定义选项的选择等)。 这两个上下文都适当地支持这些输入类型。
  4. 实现验证:验证用户输入并在验证失败时提供明确的错误消息。 这两个上下文都支持验证反馈。
  5. 使必填字段清晰:标记必填字段并为可选字段提供适当的默认值。
  6. 处理取消:始终检查用户是否取消了输入命令并妥善处理。 用户可以在仪表板和 CLI 上下文中取消。

交互上下文

交互服务的行为因解决方案的启动方式 Aspire 而异:

仪表板上下文

使用 aspire run 或直接启动 AppHost 项目的应用程序运行时,交互将在 Aspire 仪表板 Web 界面中显示。

  • 模式对话:消息框和输入提示显示为需要用户交互的覆盖对话。
  • 通知消息:信息性消息会以可关闭的横幅形式显示在仪表板的顶部。
  • 丰富的 UI:完全支持交互式表单元素、验证和视觉反馈。
  • 所有可用的方法:仪表板上下文支持所有交互服务方法。

CLI 上下文

运行 aspire publishaspire deploy时,会通过命令行界面提示进行交互。

  • 文本提示:只有输入提示(PromptInputAsyncPromptInputsAsync)可用,并在终端中显示为基于文本的提示。
  • 顺序输入:一次请求多个输入,而不是在单个对话框中请求多个输入。
  • 有限的功能:消息框、通知和确认对话框不可用,如果调用,则会引发异常。

Important

交互服务会自动适应仪表板和 CLI 上下文。 在 CLI 模式下,仅支持与输入相关的方法PromptInputAsync 以及 PromptInputsAsync- 。 在 CLI 操作中调用 PromptMessageBoxAsyncPromptNotificationAsyncPromptConfirmationAsync(例如 aspire publishaspire deploy)会导致异常。

另请参阅