Bot Framework v4-当打开2个选项卡时IndexOutOfRangeException

时间:2019-05-15 10:35:28

标签: botframework

我使用C#使用bot框架v4制作了一个bot,并且它在网页https://websitebotv2.azurewebsites.net/上,如果只有1个用户,则可以正常工作,但是当我在新标签上打开它时,它会在出现以下情况时显示IndexOutOfRangeException我开始对话。

要使它在打开多个选项卡的情况下需要做什么?

当我的漫游器启动时,它会创建一个瀑布对话框,询问名称并向用户打招呼:

public dialogBotBot(dialogBotAccessors accessors, LuisRecognizer luis, QnAMaker qna)
    {
        // Set the _accessors 
        _accessors = accessors ?? throw new ArgumentNullException(nameof(accessors));
        // The DialogSet needs a DialogState accessor, it will call it when it has a turn context.
        _dialogs = new DialogSet(accessors.ConversationDialogState);

        // This array defines how the Waterfall will execute.
        var waterfallSteps = new WaterfallStep[] {
            NameStepAsync,
            NameConfirmStepAsync,
        };

        // The incoming luis variable is the LUIS Recognizer we added above.
        this.Recognizer = luis ?? throw new System.ArgumentNullException(nameof(luis));

        // The incoming QnA variable is the QnAMaker we added above.
        this.QnA = qna ?? throw new System.ArgumentNullException(nameof(qna));

        // Add named dialogs to the DialogSet. These names are saved in the dialog state.
        _dialogs.Add(new WaterfallDialog("details", waterfallSteps));
        _dialogs.Add(new TextPrompt("name"));

    }

然后,我将他的名字保存在UserProfile类中,其中包含字段Name和Context,Context的目的是保存对话。

这是第一次运行,但是如果我打开新标签页或刷新当前标签页以进行新会话,则该漫游器会获取第一个会话数据。

在Startup.cs中抛出异常:

services.AddBot<dialogBotBot>(options =>
       {
           options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);

           // Catches any errors that occur during a conversation turn and logs them to currently
           // configured ILogger.
           ILogger logger = _loggerFactory.CreateLogger<dialogBotBot>();

           options.OnTurnError = async (context, exception) =>
           {
               logger.LogError($"Exception caught : {exception}");
               await context.SendActivityAsync(exception + "\nSorry, it looks like something went wrong.\n" + exception.Message);
           };


           // Create and add conversation state.
           var conversationState = new ConversationState(dataStore);
           options.State.Add(conversationState);

           // Create and add user state. 
           var userState = new UserState(dataStore);
           options.State.Add(userState);
       });

我的onTurnAsync方法是:

    public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    {

        // Handle Message activity type, which is the main activity type for shown within a conversational interface
        // Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
        // see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
        if (turnContext.Activity.Type == ActivityTypes.Message)
        {
            //Get the current user profile
            userProfile = await _accessors.UserProfile.GetAsync(turnContext, () => new UserProfile(), cancellationToken);

            userProfile.Contexto.Add(turnContext.Activity.Text);

            foreach (string s in userProfile.Contexto)
                await turnContext.SendActivityAsync(s);


            // Get the conversation state from the turn context.
            var state = await _accessors.CounterState.GetAsync(turnContext, () => new CounterState());

            // Bump the turn count for this conversation.
            state.TurnCount++;

            // Check LUIS model
            var recognizerResult = await this.Recognizer.RecognizeAsync(turnContext, cancellationToken);
            var topIntent = recognizerResult?.GetTopScoringIntent();
            // Get the Intent as a string
            string strIntent = (topIntent != null) ? topIntent.Value.intent : "";
            // Get the IntentScore as a double
            double dblIntentScore = (topIntent != null) ? topIntent.Value.score : 0.0;
            // Only proceed with LUIS if there is an Intent 
            // and the score for the Intent is greater than 95
            if (strIntent != "" && (dblIntentScore > 2))
            {
                switch (strIntent)
                {
                    case "None":
                        //add the bot response to contexto
                        await turnContext.SendActivityAsync("Desculpa, não percebi.");
                        break;
                    case "Utilities_Help":
                        //add the bot response to contexto
                        await turnContext.SendActivityAsync("Quero-te ajudar!\nO que precisas?");
                        break;
                    default:
                        // Received an intent we didn't expect, so send its name and score.
                        //add the bot response to contexto
                        await turnContext.SendActivityAsync($"Intent: {topIntent.Value.intent} ({topIntent.Value.score}).");
                        break;
                }
            }
            else
            {
                if (userProfile.Name == null)
                {
                    // Run the DialogSet - let the framework identify the current state of the dialog from the dialog stack and figure out what (if any) is the active dialog.
                    var dialogContext = await _dialogs.CreateContextAsync(turnContext, cancellationToken);
                    var results = await dialogContext.ContinueDialogAsync(cancellationToken);
                    // If the DialogTurnStatus is Empty we should start a new dialog.
                    if (results.Status == DialogTurnStatus.Empty)
                    {
                        await dialogContext.BeginDialogAsync("details", null, cancellationToken);
                    }
                }
                else
                {
                    var answers = await this.QnA.GetAnswersAsync(turnContext);
                    if (answers.Any() && answers[0].Score > 0.7)
                    {
                        // If the service produced one or more answers, send the first one.
                        await turnContext.SendActivityAsync(answers[0].Answer + "\n" + state.TurnCount);
                    }
                    else
                    {
                        var responseMessage = $"Ainda não sei a resposta mas vou averiguar\nPosso-te ajudar com mais alguma coisa?";

                        String connectionString = "Data Source=botdataserverv1.database.windows.net;" +
                                                 "Initial Catalog=botDataBase;" +
                                                 "User id=AzureAdmin@botdataserverv1.database.windows.net;" +
                                                 "Password=admin_123;";


                        SqlConnection connection = new SqlConnection(connectionString);

                        SqlDataAdapter adapter = new SqlDataAdapter();
                        SqlCommand command;

                        String sms = turnContext.Activity.Text;
                        float result = answers[0].Score;

                        String insertMessage = "insert into Mensagem(texto,contexto,grauCerteza)" +
                                               "values('" + sms + "', 'Falta apurar o contexto' ," + result + ")";

                        connection.Open();

                        command = new SqlCommand(insertMessage, connection);

                        adapter.InsertCommand = new SqlCommand(insertMessage, connection);
                        adapter.InsertCommand.ExecuteNonQuery();

                        command.Dispose();
                        connection.Close();


                        await turnContext.SendActivityAsync(responseMessage);
                    }
                }

                // Save the user profile updates into the user state.
                await _accessors.UserState.SaveChangesAsync(turnContext, false, cancellationToken);

                // Set the property using the accessor.
                await _accessors.CounterState.SetAsync(turnContext, state);

                // Save the new turn count into the conversation state.
                await _accessors.ConversationState.SaveChangesAsync(turnContext);
            }


        }
    }

1 个答案:

答案 0 :(得分:0)

您的问题在这里:

float result = answers[0].Score;

您有:

// Check to see if we have any answers
if (answers.Any() && answers[0].Score > 0.7)
{
    [...]
    // This is fine
}
else // else, WE HAVE NO ANSWERS
{
    [...]
    // At this point, answers is an empty array, so answers[0] throws an IndexOutOfRangeException
    float result = answers[0].Score;

刷新时发生这种情况的原因是,新选项卡的用户使用相同的用户ID。该漫游器已经知道他们的name,因此不会显示该对话框,并且在调用await this.Recognizer.RecognizeAsync(turnContext, cancellationToken);时,用户没有在新turnContext中输入任何内容,因此它返回一个空数组。

旁注:您可以使用以下方法在WebChat中设置用户ID:

window.WebChat.renderWebChat(
      {
          directLine: directLine,
          userID: "USER_ID" // Make is use Math.random() or something if you want it to be random for each refresh
      },
      this.botWindowElement.nativeElement
  );