C# Microsoft Botframework将主动消息发送给Bot(而不是用户)

C# Microsoft Botframework将主动消息发送给Bot(而不是用户),c#,botframework,C#,Botframework,我们目前正在用botframework开发一些自动化 在对话的某个时刻,我们通过服务总线发送了一些数据进行处理,等待响应,然后希望继续对话。我们已经实现了在服务总线订阅中等待响应条目的部分,然后我们希望从类型事件向bot发送活动 我们对主动消息执行了与其他帖子中描述的相同的步骤。 我们可以重新创建botclient和会话引用以及所有内容,但最终当我们发送活动时,我们总是将其发送给用户,而不是bot。但这并不会触发“” 我们实现预期结果的唯一方法是发布api/消息,但这对我们来说太复杂了,我们正在

我们目前正在用botframework开发一些自动化

在对话的某个时刻,我们通过服务总线发送了一些数据进行处理,等待响应,然后希望继续对话。我们已经实现了在服务总线订阅中等待响应条目的部分,然后我们希望从类型事件向bot发送活动

我们对主动消息执行了与其他帖子中描述的相同的步骤。 我们可以重新创建botclient和会话引用以及所有内容,但最终当我们发送活动时,我们总是将其发送给用户,而不是bot。但这并不会触发“”

我们实现预期结果的唯一方法是发布api/消息,但这对我们来说太复杂了,我们正在寻找一种比botClient(或类似技术)更简单的方法

有人有什么好主意吗?:)

ServiceBusReceiver消息处理:

private static async Task ProcessMessagesAsync(Message message, CancellationToken token)
    {
        // Process the message.
        Console.WriteLine($"Received message: SequenceNumber:{message.SystemProperties.SequenceNumber} Body:{Encoding.UTF8.GetString(message.Body)}");

        _logger?.LogInformation("Received message '{id}' with label '{label}' from queue.", message.MessageId, message.Label);


        var data = JsonSerializer.Deserialize<BotCarLicensingOrderRpaRequest>(message.Body);

        data.AdditionalData.TryGetValue("ServiceUrl", out var serviceUrl);
        data.AdditionalData.TryGetValue("ChannelId", out var channelId);
        data.AdditionalData.TryGetValue("BotId", out var botId);
        data.AdditionalData.TryGetValue("UserId", out var userId);
        data.AdditionalData.TryGetValue("ReplyToId", out var replyToId);
        var conversationReference = _offTurnConversationService.CreateSyntheticConversationReference(
            channelId?.ToString(),
            data.ConversationId,
            serviceUrl?.ToString());
        conversationReference.User = new ChannelAccount()
        {
            Id = userId?.ToString(),
            Role = "user"
        };
        conversationReference.Bot = new ChannelAccount
        {
            Id = botId?.ToString(),
            Role = "bot"
        };
        var activity = (Activity)Activity.CreateEventActivity();
        activity.Text = "success";
        activity.ChannelId = channelId?.ToString();
        activity.ServiceUrl = serviceUrl?.ToString();
        activity.RelatesTo = conversationReference;
        activity.Conversation = new ConversationAccount
        {
            Id = data.ConversationId
        };

        activity.ReplyToId = replyToId?.ToString();

        activity.ApplyConversationReference(conversationReference, true);

        // Complete the message so that it is not received again.
        // This can be done only if the subscriptionClient is created in ReceiveMode.PeekLock mode (which is the default).
        await _messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
        // This "works" but is complicated, as we have to set up a whole HTTP call
        await _offTurnConversationService.SendActivityToBotAsync(activity);
        
        // This just sends the Event to the user, no matter how I set up the conversation 
        // reference regarding From/Recipient
        // And it doesn't help in continuing the conversation
        await _offTurnConversationService.SendToConversationThroughPipelineAsync(
            async (turnContext, cancellationToken) =>
            {
                await turnContext.SendActivityAsync(activity, cancellationToken: cancellationToken);
            },
            conversationReference);
        // Note: Use the cancellationToken passed as necessary to determine if the subscriptionClient has already been closed.
        // If subscriptionClient has already been closed, you can choose to not call CompleteAsync() or AbandonAsync() etc.
        // to avoid unnecessary exceptions.
    }
private静态异步任务流程messagesasync(消息消息,取消令牌)
{
//处理消息。
Console.WriteLine($“收到的消息:SequenceNumber:{message.SystemProperties.SequenceNumber}正文:{Encoding.UTF8.GetString(message.Body)}”);
_logger?.LogInformation(“从队列中接收到带有标签“{label}”的消息“{id}”,message.MessageId,message.label);
var data=JsonSerializer.Deserialize(message.Body);
data.AdditionalData.TryGetValue(“ServiceUrl”,out var ServiceUrl);
data.AdditionalData.TryGetValue(“ChannelId”,out var ChannelId);
data.AdditionalData.TryGetValue(“BotId”,out var BotId);
data.AdditionalData.TryGetValue(“UserId”,out-var-UserId);
data.AdditionalData.TryGetValue(“ReplyToId”,out var ReplyToId);
var conversationReference=\u offTurnConversationService.CreateSyntheticConversationReference(
channelId?.ToString(),
data.ConversationId,
serviceUrl?.ToString());
conversationReference.User=新的ChannelAccount()
{
Id=userId?.ToString(),
Role=“用户”
};
conversationReference.Bot=新的ChannelAccount
{
Id=botId?.ToString(),
Role=“bot”
};
var activity=(activity)activity.CreateEventActivity();
activity.Text=“成功”;
activity.ChannelId=ChannelId?.ToString();
activity.ServiceUrl=ServiceUrl?.ToString();
activity.RelatesTo=会话参考;
activity.Conversation=新的ConversationAccount
{
Id=data.ConversationId
};
activity.ReplyToId=ReplyToId?.ToString();
activity.ApplyConversationReference(conversationReference,true);
//完成消息,使其不再被接收。
//只有在ReceiveMode.PeekLock模式(默认模式)下创建subscriptionClient时,才能执行此操作。
wait_messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
//这“可行”,但很复杂,因为我们必须设置一个完整的HTTP调用
等待关闭TurnConversationService.SendActivityToBotAsync(活动);
//这只是将事件发送给用户,无论我如何设置对话
//关于发件人/收件人的参考
//这无助于继续对话
等待\u关闭TurnConversationService.SendToConversationThroughPipelineAsync(
异步(turnContext、cancellationToken)=>
{
Wait turnContext.SendActivityAsync(活动,cancellationToken:cancellationToken);
},
会话参考);
//注意:根据需要使用传递的cancellationToken来确定subscriptionClient是否已关闭。
//如果subscriptionClient已关闭,则可以选择不调用CompleteAsync()或放弃Async()等。
//避免不必要的例外。
}
OffTurnConversationService:

public ConversationReference CreateSyntheticConversationReference(string channelId, string conversationId, string serviceUrl)
    {
        ArgumentGuard.NotNull(channelId, nameof(channelId));
        ArgumentGuard.NotNull(conversationId, nameof(conversationId));
        ArgumentGuard.NotNull(serviceUrl, nameof(serviceUrl));

        if (string.IsNullOrEmpty(_botOptions.CurrentValue.BotId))
        {
            throw new InvalidOperationException("A valid bot id must be configured in your bot options in order to create a synthetic conversation reference.");
        }

        // WARNING: This implementation works for directline and webchat.
        //          Changes could be necessary for other channels.
        var supportedChannels = new List<string>()
        {
            Channels.Directline,
            Channels.Webchat
        };
        if (supportedChannels.Any(c => c.Equals(channelId, StringComparison.OrdinalIgnoreCase)))
        {
            _logger.LogWarning(
                "The synthetic conversation reference created for channel {UsedChannel} might not work properly, " +
                "because it's not supported and tested. Supported channels are {SupportedChannel}.",
                channelId,
                string.Join(",", supportedChannels));
        }

        var conversationReference = new ConversationReference()
        {
            Conversation = new ConversationAccount()
            {
                Id = conversationId
            },
            Bot = new ChannelAccount()
            {
                Id = _botOptions.CurrentValue.BotId,
                Name = _botOptions.CurrentValue.BotId
            },
            ChannelId = channelId,
            ServiceUrl = serviceUrl
        };

        return conversationReference;
    }

public virtual async Task SendActivityToBotAsync(IActivity activity)
    {
        // Create the new request to POST to the client
        var forwardRequest = new HttpRequestMessage()
        {
            RequestUri = new Uri(_botOptions.CurrentValue.ReplyServiceUrl),
            Method = HttpMethod.Post,
        };

        // Change the host for the request to be the forwarding URL.
        forwardRequest.Headers.Host = forwardRequest.RequestUri.Host;

        // If the child bot is not running on local mode (no app-id/password), 
        // we're going send an authentication header.
        OAuthResponse authToken = await GetTokenAsync(_botOptions.CurrentValue.MicrosoftAppId, _botOptions.CurrentValue.MicrosoftAppPassword);
        forwardRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authToken.AccessToken);

        // Altered activity to JSON content
        var json = JsonConvert.SerializeObject(activity);
        var content = new StringContent(json, Encoding.UTF8, "application/json");
        forwardRequest.Content = content;

        using var client = new HttpClient();
        var response = await client.SendAsync(forwardRequest);
        if (!response.IsSuccessStatusCode)
        {
            string message = $"Failed to send activity '{activity.Id}' to client bot. {response.ReasonPhrase}";
            throw new Exception(message);
        }
    }
public virtual async Task SendToConversationThroughPipelineAsync(
        BotCallbackHandler callback,
        ConversationReference conversationReference)
    {
        ArgumentGuard.NotNull(callback, nameof(callback));
        ArgumentGuard.NotNull(conversationReference, nameof(conversationReference));

        // Avoiding 401 "Unauthorized" errors
        TrustServiceUrl(conversationReference.ServiceUrl);

        // Reuse adapter with its pipeline to send responses back to the user (like pro-active messages)
        await ((BotAdapter)_botFrameworkHttpAdapter).ContinueConversationAsync(
            _botOptions.CurrentValue.MicrosoftAppId,
            conversationReference,
            callback,
            default);
    }
public ConversationReference createSynthetical ConversationReference(字符串channelId、字符串conversationId、字符串serviceUrl)
{
ArgumentGuard.NotNull(channelId,nameof(channelId));
ArgumentGuard.NotNull(conversationId,nameof(conversationId));
ArgumentGuard.NotNull(serviceUrl,nameof(serviceUrl));
if(string.IsNullOrEmpty(_botOptions.CurrentValue.BotId))
{
抛出新的InvalidOperationException(“必须在您的bot选项中配置有效的bot id才能创建合成会话引用”);
}
//警告:此实现适用于directline和webchat。
//其他频道可能需要更改。
var supportedChannels=新列表()
{
频道,直拨电话,
频道,网络帽
};
if(supportedChannels.Any(c=>c.Equals(channelId,StringComparison.OrdinalIgnoreCase)))
{
_logger.LogWarning(
为通道{UsedChannel}创建的合成对话引用可能无法正常工作+
“因为它不受支持和测试。受支持的通道为{SupportedChannel}。”,
渠道,
Join(“,”,supportedChannels));
}
var conversationReference=新的conversationReference()
{
对话=新建对话帐户()
{
Id=会话Id
},
Bot=新的ChannelAccount()
{
Id=\u botOptions.CurrentValue.BotId,
Name=\u botOptions.CurrentValue.BotId
},
ChannelId=ChannelId,
ServiceUrl=ServiceUrl
};
返回会话引用;
}
公共虚拟异步任务SendActivityToToToToAs