如何在认证时转发用户消息

How to forward user's message on authentication

我正在使用 Bot Framework 和 AzureAuthDialog 对用户进行身份验证。

机器人首先询问用户他想要什么。每当用户写一条消息时,我们都会检查他是否经过身份验证。如果我们发现他没有认证,我们想请他认证。一旦他完成身份验证,我想继续处理他在身份验证之前的请求。

另一方面,目前发生的情况是,在用户通过身份验证后,我们丢失了用户消息。这是代码,请参阅内联注释以了解更多信息:

public class IntentHandler : LuisDialog<object>
    {
protected override async Task MessageReceived(IDialogContext context, IAwaitable<IMessageActivity> item)
        {
            if (!await context.IsUserAuthenticated(m_resourceId))
            {
// this has the user's message
                var message = await item;
// The next thing that is called here is ResumeAfterAuth function, but it does not have the user's message anymore
                await context.Forward(new AzureAuthDialog(m_resourceId), ResumeAfterAuth, message, CancellationToken.None);
            }
            else
            {
                await base.MessageReceived(context, item);
            }
        }

        private async Task ResumeAfterAuth(IDialogContext context, IAwaitable<string> item)
        {
// this does not have the users's message, it only includes "User is loged in"
                var message = await item;
                await context.PostAsync(message);
                PrivateTracer.Tracer.TraceInformation($"User {context.GetUserMail()} signed in");
                await context.PostAsync(c_welcomeQuestion);
            }
    }

知道如何在身份验证之前传递用户消息吗? 我知道我可以将用户的消息保存在 MessageReceived enter code here 的一个字段中,但这看起来太丑陋了。还有别的办法吗?

您的 ResumeAfterAuth 方法中的 IAwaitable 是您调用的对话框的结果 (AzureAuthDialog),不是初始用户的消息。

如果您不拥有 AzureAuthDialog,您需要自己保留原始消息并将其传递给回调(ResumeAfterAuth).您可以将其保留为对话框的成员变量 class 或通过 lambda 函数的闭包,如下所示:

if (!await context.IsUserAuthenticated(m_resourceId))
{    
     var initialUserText = (await item).Text;
     await context.Forward(new AzureAuthDialog(m_resourceId), (_context, _item) => ResumeAfterAuth(_context, _item, initialUserText), message, CancellationToken.None);
}

您的回调方法签名如下所示:

private async Task ResumeAfterAuth(IDialogContext context, IAwaitable<string> item, string initialUserText)

如果您拥有 AzureAuthDialog,我想您最好在完成后 return 将原始用户文本发送给您。

编辑:您将需要配置 BotFramework 以允许它序列化闭包,如果您还没有这样做,如 described here。您可以通过将此添加到服务的启动方法来实现:

var builder = new ContainerBuilder();
builder.RegisterModule(new ReflectionSurrogateModule());
builder.Update(Conversation.Container);

@andre 提到的一种方法,另一种最好的方法是将用户消息存储在局部变量中,然后在身份验证将存储的用户消息传递给它之后调用 base.MessageReceived 函数.代码通常是这样的:

class IntentHandler : LuisDialog<object>
{

    private string userToBot;

    protected override async Task MessageReceived(IDialogContext context, IAwaitable<IMessageActivity> item)
    {
        var message = await item;
        //No way to get the message in the LuisIntent methods so saving it here
        userToBot = message.Text.ToLowerInvariant();

        if (message.Type != ActivityTypes.Message)
        {
            await base.MessageReceived(context, item);

            return;
        }

        if (!await context.IsUserAuthenticated(m_resourceId))
        {
            await context.Forward(new AzureAuthDialog(m_resourceId), ResumeAfterAuth, message, CancellationToken.None);
        }
        else
        {
            await base.MessageReceived(context, item);
        }

    }

     private async Task ResumeAfterAuth(IDialogContext context, IAwaitable<string> result)
     {
        var message = await 
        await context.PostAsync(message);

        Activity activity = (Activity)context.Activity;

        //Store the saved message back to the activity
        activity.Text = userToBot;

        //Reset the saved message
        userToBot = string.Empty;

        //Call the base.MessageReceived to trigger the LUIS intenet
        await base.MessageReceived(context, Awaitable.FromItem(activity));

    }

}