Verwalten eines Vorgangs mit langer AusführungszeitManage a long-running operation

gilt für: SDK v4APPLIES TO: SDK v4

Die ordnungsgemäße Verarbeitung von Vorgängen mit langer Ausführungslast ist ein wichtiger Aspekt eines robusten Bots.Proper handling of long-running operations is an important aspect of a robust bot. Wenn der Azure Bot Service eine Aktivität von einem Kanal an Ihren Bot sendet, wird erwartet, dass der Bot die Aktivität schnell verarbeiten kann.When the Azure Bot Service sends an activity to your bot from a channel, the bot is expected to process the activity quickly. Wenn der Bot den Vorgang nicht innerhalb von 10 bis 15 Sekunden abarbeite, führt die Azure Bot Service je nach Kanal zu einem Timeout und gibt an den Client zurück, wie unter Funktionsweise von 504:GatewayTimeout Bots beschrieben.If the bot does not complete the operation within 10 to 15 seconds, depending on the channel, the Azure Bot Service will timeout and report back to the client a 504:GatewayTimeout, as described in How bots work.

In diesem Artikel wird beschrieben, wie Sie einen externen Dienst verwenden, um den Vorgang auszuführen und den Bot zu benachrichtigen, wenn er abgeschlossen ist.This article describes how to use an external service to execute the operation and to notify the bot when it has completed.

VoraussetzungenPrerequisites

Informationen zu diesem BeispielAbout this sample

Dieser Artikel beginnt mit dem Beispielbot für Eingabeaufforderungen mit mehreren Durchlaufen und fügt Code zum Ausführen von Vorgängen mit langer Ausführungsausführung hinzu.This article begins with the multi-turn prompt sample bot and adds code for performing a long-running operations. Außerdem wird veranschaulicht, wie nach Abschluss des Vorgangs auf einen Benutzer reagiert wird.It also demonstrates how to respond to a user after the operation has completed. Im aktualisierten Beispiel:In the updated sample:

  • Der Bot fragt den Benutzer, welcher Vorgang mit langer Laufzeit ausgeführt werden soll.The bot asks the user which long-running operation to perform.
  • Der Bot empfängt eine Aktivität vom Benutzer und bestimmt, welcher Vorgang durchgeführt werden soll.The bot receives an activity from the user, and determines which operation to perform.
  • Der Bot benachrichtigt den Benutzer, dass der Vorgang einige Zeit in Betrieb nimmt, und sendet den Vorgang an eine C#-Funktion.The bot notifies the user the operation will take some time and sends the operation off to a C# function.
    • Der Bot speichert den Zustand und gibt an, dass ein Vorgang durchgeführt wird.The bot saves state, indicating there is an operation in progress.
    • Während der Vorgang ausgeführt wird, antwortet der Bot auf Nachrichten des Benutzers und benachrichtigt den Benutzer, dass der Vorgang noch ausgeführt wird.While the operation is running, the bot responds to messages from the user, notifying them the operation is still in progress.
    • Azure Functions verwaltet den Vorgang mit langer Ausführung und sendet eine Aktivität an den Bot und benachrichtigt ihn, dass event der Vorgang abgeschlossen wurde.Azure Functions manages the long-running operation and sends an event activity to the bot, notifying it that the operation completed.
  • Der Bot setzt die Konversation wieder auf und sendet eine proaktive Nachricht, um den Benutzer zu benachrichtigen, dass der Vorgang abgeschlossen wurde.The bot resumes the conversation and sends a proactive message to notify the user that the operation completed. Der Bot spricht dann den zuvor erwähnten Vorgangsstatus aus.The bot then clears the operation state mentioned earlier.

In diesem Beispiel wird eine LongOperationPrompt Klasse definiert, die von der abstrakten Klasse abgeleitet ActivityPrompt wird.This example defines a LongOperationPrompt class, derived from the abstract ActivityPrompt class. Wenn der die zu verarbeitende Aktivität in die Warteschlange einreiht, enthält er eine Auswahl des Benutzers in der LongOperationPrompt value-Eigenschaft der Aktivität.When the LongOperationPrompt queues the activity to be processed, it includes a choice from the user within the activity's value property. Diese Aktivität wird dann von einem Azure Functions, geändert und in eine andere Aktivität umschlossen, bevor sie mithilfe eines Direct Line an event den Bot zurücksandt wird.This activity is then consumed by Azure Functions, modified, and wrapped in a different event activity before it is sent back to the bot using a Direct Line client. Innerhalb des Bots wird die Ereignisaktivität verwendet, um die Konversation durch Aufrufen der Continue Conversation-Methode des Adapters fortzufahren.Within the bot, the event activity is used to resume the conversation by calling the adapter's continue conversation method. Der Dialogstapel wird dann geladen, und der LongOperationPrompt ist abgeschlossen.The dialog stack is then loaded, and the LongOperationPrompt completes.

In diesem Artikel werden viele verschiedene Technologien behandelt.This article touches on many different technologies. Links zu zugehörigen Artikeln finden Sie im Abschnitt "Zusätzliche Ressourcen".See the additional resources section for links to associated articles.

Erstellen eines Azure-SpeicherkontosCreate an Azure Storage account

Erstellen Sie ein Azure Storage Konto, und rufen Sie die Verbindungszeichenfolge ab.Create an Azure Storage account, and retrieve the connection string. Sie müssen die Verbindungszeichenfolge der Konfigurationsdatei Ihres Bots hinzufügen.You will need to add the connection string to your bot's configuration file.

Weitere Informationen finden Sie unter Erstellen eines Speicherkontos und Kopieren Ihrer Anmeldeinformationen aus Azure-Portal.For more information, see create a storage account and copy your credentials from the Azure portal.

Erstellen einer Bot Channels RegistrationCreate a Bot Channels Registration

  1. Richten Sie vor dem Erstellen der Registrierung ngrok ein, und rufen Sie eine URL ab, die während des lokalen Debuggens als Messagingendpunkt des Bots verwendet werden soll.Before creating the registration, setup ngrok and retrieve a URL to be used as the bot's messaging endpoint during local debugging. Der Messagingendpunkt ist die HTTPS-Weiterleitungs-URL mit /api/messages/ angefügter .The messaging endpoint will be the HTTPS forwarding URL with /api/messages/ appended. Beachten Sie, dass der Standardport für neue Bots 3978 ist.Note that the default port for new bots is 3978.

    Weitere Informationen finden Sie unter Debuggen eines Bots mithilfe von ngrok.For more information, see how to debug a bot using ngrok.

  2. Erstellen Sie eine Botkanalregistrierung im Azure-Portal oder mit dem Azure CLI.Create a Bot Channels Registration in the Azure portal or with the Azure CLI. Legen Sie den Messagingendpunkt des Bots auf den Endpunkt fest, den Sie mit ngrok erstellt haben.Set the bot's messaging endpoint to the one you created with ngrok. Nachdem die Botkanalregistrierungsressource erstellt wurde, erhalten Sie die Microsoft-App-ID und das Kennwort des Bots.After the Bot Channels Registration resource is created, obtain the bot's Microsoft app ID and password. Aktivieren Sie den Direct Line Kanal, und rufen Sie ein Direct Line ab.Enable the Direct Line channel, and retrieve a Direct Line secret. Sie fügen diese ihrem Botcode und Ihrer C#-Funktion hinzu.You will add these to your bot code and C# function.

    Weitere Informationen finden Sie unter Verwalten eines Bots und Verbinden eines Bots mit Direct Line.For more information, see how to manage a bot and how to connect a bot to Direct Line.

Erstellen der C#-FunktionCreate the C# function

  1. Erstellen Sie Azure Functions-App basierend auf dem .NET Core Runtimestapel.Create an Azure Functions app based on the .Net Core runtime stack.

    Weitere Informationen finden Sie unter Erstellen einer Funktions-App und in Azure Functions C#-Skriptreferenz.For more information, see how to create a function app and the Azure Functions C# script reference.

  2. Fügen Sie DirectLineSecret der Funktions-App eine Anwendungseinstellung hinzu.Add a DirectLineSecret application setting to the Function App.

    Weitere Informationen finden Sie unter Verwalten Ihrer Funktions-App.For more information, see how to manage your function app.

  3. Fügen Sie in der Funktions-App eine Funktion hinzu, die auf der Azure Queue Storage basiert.Within the Function App, add a function based on the Azure Queue Storage template.

    Legen Sie den gewünschten Warteschlangennamen fest, und wählen Sie den Azure Storage Account aus, der in einem früheren Schritt erstellt wurde.Set the desired queue name, and choose the Azure Storage Account created in an earlier step. Dieser Warteschlangenname wird auch in der Datei des Botsappsettings.js gespeichert.This queue name will also be placed in the bot's appsettings.json file.

  4. Fügen Sie der Funktion die Datei function.proj hinzu.Add a function.proj file to the function.

    <Project Sdk="Microsoft.NET.Sdk">
        <PropertyGroup>
            <TargetFramework>netstandard2.0</TargetFramework>
        </PropertyGroup>
    
        <ItemGroup>
            <PackageReference Include="Microsoft.Bot.Connector.DirectLine" Version="3.0.2" />
            <PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.4" />
        </ItemGroup>
    </Project>
    
  5. Aktualisieren Sie run.csx mit dem folgenden Code:Update run.csx with the following code:

    #r "Newtonsoft.Json"
    
    using System;
    using System.Net.Http;
    using System.Text;
    using Newtonsoft.Json;
    using Microsoft.Bot.Connector.DirectLine;
    using System.Threading;
    
    public static async Task Run(string queueItem, ILogger log)
    {
        log.LogInformation($"C# Queue trigger function processing");
    
        JsonSerializerSettings jsonSettings = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore };
        var originalActivity =  JsonConvert.DeserializeObject<Activity>(queueItem, jsonSettings);
        // Perform long operation here....
        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(15));
    
        if(originalActivity.Value.ToString().Equals("option 1", CompareOptions.OrdinalIgnoreCase))
        {
            originalActivity.Value = " (Result for long operation one!)";
        }
        else if(originalActivity.Value.ToString().Equals("option 2", CompareOptions.OrdinalIgnoreCase))
        {
            originalActivity.Value = " (A different result for operation two!)";
        }
    
        originalActivity.Value = "LongOperationComplete:" + originalActivity.Value;
        var responseActivity =  new Activity("event");
        responseActivity.Value = originalActivity;
        responseActivity.Name = "LongOperationResponse";
        responseActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
    
        var directLineSecret = Environment.GetEnvironmentVariable("DirectLineSecret");
        using(DirectLineClient client = new DirectLineClient(directLineSecret))
        {
            var conversation = await client.Conversations.StartConversationAsync();
            await client.Conversations.PostActivityAsync(conversation.ConversationId, responseActivity);
        }
    
        log.LogInformation($"Done...");
    }
    

Erstellen des BotsCreate the bot

  1. Beginnen Sie mit einer Kopie des C#-Beispiels für mehrfache Eingabeaufforderungen.Start with a copy of the C# Multi-Turn-Prompt sample.

  2. Fügen Sie Ihrem Projekt das NuGet-Paket Azure.Storage.Queues hinzu.Add the Azure.Storage.Queues NuGet package to your project.

  3. Fügen Sie der Konfigurationsdatei Ihres Bots die Verbindungszeichenfolge für Azure Storage konto, das Sie zuvor erstellt haben, und den Namen der Speicherwarteschlange hinzu.Add the connection string for the Azure Storage account you created earlier, and the Storage Queue Name, to your bot's configuration file.

    Stellen Sie sicher, dass der Warteschlangenname mit dem Namen identisch ist, den Sie zuvor zum Erstellen der Warteschlangentriggerfunktion verwendet haben.Ensure the queue name is the same as the one you used to create the Queue Trigger Function earlier. Fügen Sie außerdem die Werte für die Eigenschaften und hinzu, die Sie zuvor beim MicrosoftAppId MicrosoftAppPassword Erstellen der Botkanalregistrierungsressource generiert haben.Also add the values for the MicrosoftAppId and MicrosoftAppPassword properties that you generated earlier when you created the Bot Channels Registration resource.

    appsettings.jsonappsettings.json

    {
      "MicrosoftAppId": "<your-bot-app-id>",
      "MicrosoftAppPassword": "<your-bot-app-password>",
      "StorageQueueName": "<your-azure-storage-queue-name>",
      "QueueStorageConnection": "<your-storage-connection-string>"
    }
    
  4. Fügen Sie IConfiguration dialogbot.cs einen Parameter hinzu, um MicrsofotAppId abzurufen.Add an IConfiguration parameter to DialogBot.cs in order to retrieve the MicrsofotAppId. Fügen Sie außerdem OnEventActivityAsync einen Handler für aus der LongOperationResponse Azure-Funktion hinzu.Also add an OnEventActivityAsync handler for the LongOperationResponse from the Azure Function.

    Bots\DialogBot.csBots\DialogBot.cs

    protected readonly IStatePropertyAccessor<DialogState> DialogState;
    protected readonly Dialog Dialog;
    protected readonly BotState ConversationState;
    protected readonly ILogger Logger;
    private readonly string _botId;
    
    /// <summary>
    /// Create an instance of <see cref="DialogBot{T}"/>.
    /// </summary>
    /// <param name="configuration"><see cref="IConfiguration"/> used to retrieve MicrosoftAppId
    /// which is used in ContinueConversationAsync.</param>
    /// <param name="conversationState"><see cref="ConversationState"/> used to store the DialogStack.</param>
    /// <param name="dialog">The RootDialog for this bot.</param>
    /// <param name="logger"><see cref="ILogger"/> to use.</param>
    public DialogBot(IConfiguration configuration, ConversationState conversationState, T dialog, ILogger<DialogBot<T>> logger)
    {
        _botId = configuration["MicrosoftAppId"] ?? Guid.NewGuid().ToString();
        ConversationState = conversationState;
        Dialog = dialog;
        Logger = logger;
        DialogState = ConversationState.CreateProperty<DialogState>(nameof(DialogState));
    }
    
    public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
    {
        await base.OnTurnAsync(turnContext, cancellationToken);
    
        // Save any state changes that might have occurred during the turn.
        await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    }
    
    protected override async Task OnEventActivityAsync(ITurnContext<IEventActivity> turnContext, CancellationToken cancellationToken)
    {
        // The event from the Azure Function will have a name of 'LongOperationResponse'
        if (turnContext.Activity.ChannelId == Channels.Directline && turnContext.Activity.Name == "LongOperationResponse")
        {
            // The response will have the original conversation reference activity in the .Value
            // This original activity was sent to the Azure Function via Azure.Storage.Queues in AzureQueuesService.cs.
            var continueConversationActivity = (turnContext.Activity.Value as JObject)?.ToObject<Activity>();
            await turnContext.Adapter.ContinueConversationAsync(_botId, continueConversationActivity.GetConversationReference(), async (context, cancellation) =>
            {
                Logger.LogInformation("Running dialog with Activity from LongOperationResponse.");
    
                // ContinueConversationAsync resets the .Value of the event being continued to Null, 
                //so change it back before running the dialog stack. (The .Value contains the response 
                //from the Azure Function)
                context.Activity.Value = continueConversationActivity.Value;
                await Dialog.RunAsync(context, DialogState, cancellationToken);
    
                // Save any state changes that might have occurred during the inner turn.
                await ConversationState.SaveChangesAsync(context, false, cancellationToken);
            }, cancellationToken);
        }
        else
        {
            await base.OnEventActivityAsync(turnContext, cancellationToken);
        }
    }
    
  5. Erstellen Sie einen Azure Queues-Dienst, um Aktivitäten in die Warteschlange zu stellen, die verarbeitet werden müssen.Create an Azure Queues service to queue activities which need to be processed.

    AzureQueuesService.csAzureQueuesService.cs

    /// <summary>
    /// Service used to queue messages to an Azure.Storage.Queues.
    /// </summary>
    public class AzureQueuesService
    {
        private static JsonSerializerSettings jsonSettings = new JsonSerializerSettings()
            {
                Formatting = Formatting.Indented,
                NullValueHandling = NullValueHandling.Ignore
            };
    
        private bool _createQueuIfNotExists = true;
        private readonly QueueClient _queueClient;
    
        /// <summary>
        /// Creates a new instance of <see cref="AzureQueuesService"/>.
        /// </summary>
        /// <param name="config"><see cref="IConfiguration"/> used to retrieve
        /// StorageQueueName and QueueStorageConnection from appsettings.json.</param>
        public AzureQueuesService(IConfiguration config)
        {
            var queueName = config["StorageQueueName"];
            var connectionString = config["QueueStorageConnection"];
    
            _queueClient = new QueueClient(connectionString, queueName);
        }
    
        /// <summary>
        /// Queue and Activity, with option in the Activity.Value to Azure.Storage.Queues
        ///
        /// <seealso cref="https://github.com/microsoft/botbuilder-dotnet/blob/master/libraries/Microsoft.Bot.Builder.Azure/Queues/ContinueConversationLater.cs"/>
        /// </summary>
        /// <param name="referenceActivity">Activity to queue after a call to GetContinuationActivity.</param>
        /// <param name="option">The option the user chose, which will be passed within the .Value of the activity queued.</param>
        /// <param name="cancellationToken">Cancellation token for the async operation.</param>
        /// <returns>Queued <see cref="Azure.Storage.Queues.Models.SendReceipt.MessageId"/>.</returns>
        public async Task<string> QueueActivityToProcess(Activity referenceActivity, string option, CancellationToken cancellationToken)
        {
            if (_createQueuIfNotExists)
            {
                _createQueuIfNotExists = false;
                await _queueClient.CreateIfNotExistsAsync().ConfigureAwait(false);
            }
    
            // create ContinuationActivity from the conversation reference.
            var activity = referenceActivity.GetConversationReference().GetContinuationActivity();
            // Pass the user's choice in the .Value
            activity.Value = option;
    
            var message = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(activity, jsonSettings)));
    
            // Aend ResumeConversation event, it will get posted back to us with a specific value, giving us 
            // the ability to process it and do the right thing.
            var reciept = await _queueClient.SendMessageAsync(message, cancellationToken).ConfigureAwait(false);
            return reciept.Value.MessageId;
        }
    }
    

DialogfelderDialogs

Entfernen Sie den alten Dialog, und ersetzen Sie ihn durch neue Dialoge, um die Vorgänge zu unterstützen.Remove the old dialog and replace it with new dialogs to support the operations.

  1. Entfernen Sie die Datei UserProfileDialog.cs.Remove the UserProfileDialog.cs file.

  2. Fügen Sie ein benutzerdefiniertes Eingabeaufforderungsdialogfeld hinzu, in dem der Benutzer gefragt wird, welcher Vorgang durchgeführt werden soll.Add a custom prompt dialog that asks the user which operation to perform.

    Dialogs\LongOperationPrompt.csDialogs\LongOperationPrompt.cs

    /// <summary>
    /// <see cref="ActivityPrompt"/> implementation which will queue an activity,
    /// along with the <see cref="LongOperationPromptOptions.LongOperationOption"/>,
    /// and wait for an <see cref="ActivityTypes.Event"/> with name of "ContinueConversation"
    /// and Value containing the text: "LongOperationComplete".
    ///
    /// The result of this prompt will be the received Event Activity, which is sent by
    /// the Azure Function after it finishes the long operation.
    /// </summary>
    public class LongOperationPrompt : ActivityPrompt
    {
        private readonly AzureQueuesService _queueService;
    
        /// <summary>
        /// Create a new instance of <see cref="LongOperationPrompt"/>.
        /// </summary>
        /// <param name="dialogId">Id of this <see cref="LongOperationPrompt"/>.</param>
        /// <param name="validator">Validator to use for this prompt.</param>
        /// <param name="queueService"><see cref="AzureQueuesService"/> to use for Enqueuing the activity to process.</param>
        public LongOperationPrompt(string dialogId, PromptValidator<Activity> validator, AzureQueuesService queueService) 
            : base(dialogId, validator)
        {
            _queueService = queueService;
        }
    
        public async override Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options, CancellationToken cancellationToken = default)
        {
            // When the dialog begins, queue the option chosen within the Activity queued.
            await _queueService.QueueActivityToProcess(dc.Context.Activity, (options as LongOperationPromptOptions).LongOperationOption, cancellationToken);
    
            return await base.BeginDialogAsync(dc, options, cancellationToken);
        }
    
        protected override Task<PromptRecognizerResult<Activity>> OnRecognizeAsync(ITurnContext turnContext, IDictionary<string, object> state, PromptOptions options, CancellationToken cancellationToken = default)
        {
            var result = new PromptRecognizerResult<Activity>() { Succeeded = false };
    
            if(turnContext.Activity.Type == ActivityTypes.Event
                && turnContext.Activity.Name == "ContinueConversation"
                && turnContext.Activity.Value != null
                // Custom validation within LongOperationPrompt.  
                // 'LongOperationComplete' is added to the Activity.Value in the Queue consumer (See: Azure Function)
                && turnContext.Activity.Value.ToString().Contains("LongOperationComplete", System.StringComparison.InvariantCultureIgnoreCase))
            {
                result.Succeeded = true;
                result.Value = turnContext.Activity;
            }
    
            return Task.FromResult(result);
        }
    }
    
  3. Fügen Sie eine Eingabeaufforderungsoptionen-Klasse für die benutzerdefinierte Eingabeaufforderung hinzu.Add a prompt options class for the custom prompt.

    Dialogs\LongOperationPromptOptions.csDialogs\LongOperationPromptOptions.cs

    /// <summary>
    /// Options sent to <see cref="LongOperationPrompt"/> demonstrating how a value
    /// can be passed along with the queued activity.
    /// </summary>
    public class LongOperationPromptOptions : PromptOptions
    {
        /// <summary>
        /// This is a property sent through the Queue, and is used
        /// in the queue consumer (the Azure Function) to differentiate 
        /// between long operations chosen by the user.
        /// </summary>
        public string LongOperationOption { get; set; }
    }
    
  4. Fügen Sie das Dialogfeld hinzu, das die benutzerdefinierte Eingabeaufforderung verwendet, um die Auswahl des Benutzers zu erhalten, und initiiert den Vorgang mit langer Laufzeit.Add the dialog that uses the custom prompt to get the user's choice and initiates the long-running operation.

    Dialogs\LongOperationDialog.csDialogs\LongOperationDialog.cs

    /// <summary>
    /// This dialog demonstrates how to use the <see cref="LongOperationPrompt"/>.
    ///
    /// The user is provided an option to perform any of three long operations.
    /// Their choice is then sent to the <see cref="LongOperationPrompt"/>.
    /// When the prompt completes, the result is received as an Activity in the
    /// final Waterfall step.
    /// </summary>
    public class LongOperationDialog : ComponentDialog
    {
        public LongOperationDialog(AzureQueuesService queueService)
            : base(nameof(LongOperationDialog))
        {
            // This array defines how the Waterfall will execute.
            var waterfallSteps = new WaterfallStep[]
            {
                OperationTimeStepAsync,
                LongOperationStepAsync,
                OperationCompleteStepAsync,
            };
    
            // Add named dialogs to the DialogSet. These names are saved in the dialog state.
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
            AddDialog(new LongOperationPrompt(nameof(LongOperationPrompt), (vContext, token) =>
            {
                return Task.FromResult(vContext.Recognized.Succeeded);
            }, queueService));
            AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
    
            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }
    
        private static async Task<DialogTurnResult> OperationTimeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            // WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
            // Running a prompt here means the next WaterfallStep will be run when the user's response is received.
            return await stepContext.PromptAsync(nameof(ChoicePrompt),
                new PromptOptions
                {
                    Prompt = MessageFactory.Text("Please select a long operation test option."),
                    Choices = ChoiceFactory.ToChoices(new List<string> { "option 1", "option 2", "option 3" }),
                }, cancellationToken);
        }
    
        private static async Task<DialogTurnResult> LongOperationStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            var value = ((FoundChoice)stepContext.Result).Value;
            stepContext.Values["longOperationOption"] = value;
    
            var prompt = MessageFactory.Text("...one moment please....");
            // The reprompt will be shown if the user messages the bot while the long operation is being performed.
            var retryPrompt = MessageFactory.Text($"Still performing the long operation: {value} ... (is the Azure Function executing from the queue?)");
            return await stepContext.PromptAsync(nameof(LongOperationPrompt),
                                                        new LongOperationPromptOptions
                                                        {
                                                            Prompt = prompt,
                                                            RetryPrompt = retryPrompt,
                                                            LongOperationOption = value,
                                                        }, cancellationToken);
        }
    
        private static async Task<DialogTurnResult> OperationCompleteStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
        {
            stepContext.Values["longOperationResult"] = stepContext.Result;
            await stepContext.Context.SendActivityAsync(MessageFactory.Text($"Thanks for waiting. { (stepContext.Result as Activity).Value}"), cancellationToken);
    
            // Start over by replacing the dialog with itself.
            return await stepContext.ReplaceDialogAsync(nameof(WaterfallDialog), null, cancellationToken);
        }
    }
    

Registrieren von Diensten und DialogRegister services and Dialog

Aktualisieren Sie in Startup.cs die -Methode, ConfigureServices um zu LongOperationDialog registrieren, und fügen Sie AzureQueuesService hinzu.In Startup.cs, update the ConfigureServices method to register the LongOperationDialog and add the AzureQueuesService.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers().AddNewtonsoftJson();

    // Create the Bot Framework Adapter with error handling enabled.
    services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

    // In production, this should be a persistent storage provider.bot
    services.AddSingleton<IStorage>(new MemoryStorage());

    // Create the Conversation state. (Used by the Dialog system itself.)
    services.AddSingleton<ConversationState>();

    // The Dialog that will be run by the bot.
    services.AddSingleton<LongOperationDialog>();

    // Service used to queue into Azure.Storage.Queues
    services.AddSingleton<AzureQueuesService>();

    // Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
    services.AddTransient<IBot, DialogBot<LongOperationDialog>>();
}

So testen Sie den BotTo test the bot

  1. Installieren Sie Bot Framework Emulator (sofern noch nicht geschehen).If you have not done so already, install the Bot Framework Emulator.

  2. Führen Sie das Beispiel lokal auf Ihrem Computer aus.Run the sample locally on your machine.

  3. Starten Sie den Emulator, stellen Sie eine Verbindung mit Ihrem Bot her, und senden Sie Nachrichten wie unten dargestellt.Start the Emulator, connect to your bot, and send messages as shown below.

    Bot-Beispiel

Zusätzliche RessourcenAdditional resources

Tool oder FeatureTool or feature RessourcenResources
Azure-FunktionenAzure Functions Erstellen einer Funktions-AppCreate a function app
Azure Functions C#-SkriptAzure Functions C# script
Verwalten Ihrer Funktions-AppManage your function app
Azure-PortalAzure portal Verwalten eines BotsManage a bot
Herstellen der Verbindung eines Bots mit Direct LineConnect a bot to Direct Line
Azure StorageAzure Storage Azure Queue StorageAzure Queue Storage
Erstellen eines SpeicherkontosCreate a storage account
Kopieren Ihrer Anmeldeinformationen aus dem Azure-PortalCopy your credentials from the Azure portal
Verwenden von WarteschlangenHow to Use Queues
Bot-GrundlagenBot basics Funktionsweise von BotsHow bots work
Eingabeaufforderungen in WasserfalldialogenPrompts in waterfall dialogs
Proaktives MessagingProactive messaging
ngrokngrok Debuggen eines Bots mit ngrokDebug a bot using ngrok