简体   繁体   English

无法将参数传递给 ContinueConversationAsync 方法内的 BotCallback

[英]Cannot pass arguments to a BotCallback inside a ContinueConversationAsync method

I am trying to implement proactive messages on bot framework v4, It works, but only with the string on the BotCallback function, I need to pass custom text but ContinueConversationAsync doesnt seems to allow it我正在尝试在 bot 框架 v4 上实现主动消息,它可以工作,但只能使用 BotCallback 函数上的字符串,我需要传递自定义文本,但 ContinueConversationAsync 似乎不允许它

        public async Task<bool> SendProactiveMessage(MensajeExterno mensajeExterno)
    {

            var referenciaDeConversacion = ObtenerReferenciaConversacion(mensajeExterno.ConversationId);
            var continuationActivity = referenciaDeConversacion.GetContinuationActivity();
            if (referenciaDeConversacion == null) return false;


            await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, referenciaDeConversacion, BotCallback, default(CancellationToken));

            return true;

    }

    private ConversationReference ObtenerReferenciaConversacion(string conversationId)
    {
        return new ConversationReferenceModulo().ObtenerConversationReference(conversationId);
    }

    public MensajeroDefaultModulo(IBotFrameworkHttpAdapter adapter, IConfiguration configuration)
    {
        _adapter = adapter;
        _appId = configuration["MicrosoftAppId"];

        if (string.IsNullOrEmpty(_appId))
        {
            _appId = Guid.NewGuid().ToString(); //if no AppId, use a random Guid
        }
    }

    private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
    {
        var activity = turnContext.Activity;
        await turnContext.SendActivityAsync("proactive hello", cancellationToken: cancellationToken);
    }

You can make a wrapper around BotCallback using LINQ approach.您可以使用 LINQ 方法对 BotCallback 进行包装。 But personally i do not understand the idea of such delegates without any EventArgs.但我个人不理解没有任何 EventArgs 的代表的想法。

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] string messageText)
    {
        foreach (var conversationReference in _conversationReferences.Values)
        {
            await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, async (context, token) => await BotCallback(messageText, context, token), default(CancellationToken));
        }

        return new ContentResult()
        {
            Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
            ContentType = "text/html",
            StatusCode = (int)HttpStatusCode.OK,
        };
    }

    private async Task BotCallback(string message, ITurnContext turnContext, CancellationToken cancellationToken)
    {
        await turnContext.SendActivityAsync(message, cancellationToken: cancellationToken);
    }

What I understand you are wanting to do is to pass a value to the BotCallback that can be sent back via the method SendActivityAsync.我知道您想要做的是将一个值传递给 BotCallback,该值可以通过方法 SendActivityAsync 发回。

To do this you can use a lambda expression instead of calling the BotCallback.为此,您可以使用 lambda 表达式而不是调用 BotCallback。

public async Task<bool> SendProactiveMessage(MensajeExterno mensajeExterno)
{
        var yourVariable = "blah";

        var referenciaDeConversacion = ObtenerReferenciaConversacion(mensajeExterno.ConversationId);
        var continuationActivity = referenciaDeConversacion.GetContinuationActivity();
        if (referenciaDeConversacion == null) return false;


        await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, referenciaDeConversacion, async (context, token) => { 
await turnContext.SendActivityAsync("proactive hello " + yourVariable, cancellationToken: cancellationToken); 
}, default(CancellationToken));
        return true;
}

This comes from this reference to a proactive messaging sample here: https://github.com/microsoft/botbuilder-dotnet/issues/787这来自对此处主动消息传递示例的引用: https : //github.com/microsoft/botbuilder-dotnet/issues/787

For Lambda expressions see Lambda Expressions (C# Programming Guide)有关 Lambda 表达式,请参阅Lambda 表达式(C# 编程指南)

A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types. Lambda 表达式是一个匿名函数,可以包含表达式和语句,可用于创建委托或表达式树类型。

All lambda expressions use the lambda operator =>, which is read as "goes to".所有 lambda 表达式都使用 lambda 运算符 =>,它被读作“goes to”。 The left side of the lambda operator specifies the input parameters (if any) and the right side holds the expression or statement block. lambda 运算符的左侧指定输入参数(如果有),右侧保存表达式或语句块。 The lambda expression x => x * x is read "x goes to x times x." lambda 表达式 x => x * x 读作“x 到 x 乘以 x”。

Updated with API controller example更新了 API 控制器示例

The SendProactiveMessage needs to be in a Controller in your Bot project, for example: SendProactiveMessage 需要在您的 Bot 项目中的控制器中,例如:

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;

namespace ProactiveBot.Controllers
{
    [Route("api/notify")]
    [ApiController]
    public class NotifyController : ControllerBase
    {
        private readonly IBotFrameworkHttpAdapter _adapter;
        private readonly string _appId;
        private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;
    public NotifyController(IBotFrameworkHttpAdapter adapter, IConfiguration configuration, ConcurrentDictionary<string, ConversationReference> conversationReferences)
    {
        _adapter = adapter;
        _conversationReferences = conversationReferences;
        _appId = configuration["MicrosoftAppId"];

        // If the channel is the Emulator, and authentication is not in use,
        // the AppId will be null.  We generate a random AppId for this case only.
        // This is not required for production, since the AppId will have a value.
        if (string.IsNullOrEmpty(_appId))
        {
            _appId = Guid.NewGuid().ToString(); //if no AppId, use a random Guid
        }
    }

    public async Task<IActionResult> Get([FromQuery(Name = "taskID")] int taskID)
    {            

        foreach (var conversationReference in _conversationReferences.Values)
        {                

            await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, async (context, token) => {
                await context.SendActivityAsync("proactive task notification for TaskID: " + taskID.ToString());
            }, default(CancellationToken));
        }


        // Let the caller know proactive messages have been sent
        return new ContentResult()
        {
            Content = "<html><body><h1>Proactive messages have been sent.</h1><p>" + taskID.ToString() + "</p></body></html>",
            ContentType = "text/html",
            StatusCode = (int)HttpStatusCode.OK,
        };
    }

}

} }

You can then get access to the context and token through the injected adapter.然后,您可以通过注入的适配器访问上下文和令牌。 The above code is largely from the current Proactive Message sample code上面的代码主要来自当前的Proactive Message 示例代码

So I can then call this API eg.所以我可以调用这个 API,例如。 http://localhost:3988/api/notify?taskID=5678 passing in the taskID parameter (in my case) which is then sent through to the user via ContinueConversationAsync. http://localhost:3988/api/notify?taskID=5678传入 taskID 参数(在我的例子中),然后通过 ContinueConversationAsync 发送给用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM