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