C# 如何使用Asp.net内核使用QnA Bot实现切换
我已经实现了QnA功能,但无法实现机器人向人类的切换。这是一个场景 如果用户因为对bot不满意而希望连接到代理,则会将请求委托给bot 这是QNA制造商代码。有人能提出这个建议吗 //版权所有(c)微软公司。版权所有。 //根据麻省理工学院许可证授权C# 如何使用Asp.net内核使用QnA Bot实现切换,c#,azure,asp.net-core,botframework,C#,Azure,Asp.net Core,Botframework,我已经实现了QnA功能,但无法实现机器人向人类的切换。这是一个场景 如果用户因为对bot不满意而希望连接到代理,则会将请求委托给bot 这是QNA制造商代码。有人能提出这个建议吗 //版权所有(c)微软公司。版权所有。 //根据麻省理工学院许可证授权 using Microsoft.Bot.Builder; using Microsoft.Bot.Builder.AI.QnA; using Microsoft.Bot.Builder.Dialogs; using Microsoft.Bot.Co
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.AI.QnA;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.Configuration;
using NCIBot;
using NCIBot.Bots;
using NCIBot.CommandHandling;
using NCIBot.ConversationHistory;
using NCIBot.MessageRouting;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Underscore.Bot.MessageRouting;
using Underscore.Bot.MessageRouting.DataStore;
using Underscore.Bot.MessageRouting.DataStore.Azure;
using Underscore.Bot.MessageRouting.DataStore.Local;
using Underscore.Bot.MessageRouting.Results;
namespace Microsoft.BotBuilderSamples.Bots
{
public class QnABot<T> : ActivityHandler where T : Microsoft.Bot.Builder.Dialogs.Dialog
{
protected readonly BotState ConversationState;
protected readonly Bot.Builder.Dialogs.Dialog Dialog;
protected readonly BotState UserState;
protected readonly CosmosTranscriptStore TranscriptStore;
private const string KeyRejectConnectionRequestIfNoAggregationChannel = "RejectConnectionRequestIfNoAggregationChannel";
private const string KeyPermittedAggregationChannels = "PermittedAggregationChannels";
private const string KeyNoDirectConversationsWithChannels = "NoDirectConversationsWithChannels";
public IConfiguration Configuration
{
get;
protected set;
}
public MessageRouter MessageRouter
{
get;
protected set;
}
public MessageRouterResultHandler MessageRouterResultHandler
{
get;
protected set;
}
public CommandHandler CommandHandler
{
get;
protected set;
}
public MessageLogs MessageLogs
{
get;
protected set;
}
public QnABot(ConversationState conversationState, UserState userState, T dialog, CosmosTranscriptStore transcriptStore, IConfiguration config)
{
ConversationState = conversationState;
UserState = userState;
Dialog = dialog;
TranscriptStore = transcriptStore;
string connectionString = ""; // Configuration[KeyAzureTableStorageConnectionString];
Configuration = config;
IRoutingDataStore routingDataStore = null;
if (string.IsNullOrEmpty(connectionString))
{
System.Diagnostics.Debug.WriteLine($"WARNING!!! No connection string found - using {nameof(InMemoryRoutingDataStore)}");
routingDataStore = new InMemoryRoutingDataStore();
}
else
{
System.Diagnostics.Debug.WriteLine($"Found a connection string - using {nameof(AzureTableRoutingDataStore)}");
routingDataStore = new AzureTableRoutingDataStore(connectionString);
}
MessageRouter = new MessageRouter(
routingDataStore,
new MicrosoftAppCredentials(Configuration["MicrosoftAppId"], Configuration["MicrosoftAppPassword"]));
//MessageRouter.Logger = new Logging.AggregationChannelLogger(MessageRouter);
ConnectionRequestHandler connectionRequestHandler =
new ConnectionRequestHandler(GetChannelList(KeyNoDirectConversationsWithChannels));
MessageRouterResultHandler = new MessageRouterResultHandler(MessageRouter);
CommandHandler = new CommandHandler(
MessageRouter,
MessageRouterResultHandler,
connectionRequestHandler,
GetChannelList(KeyPermittedAggregationChannels));
//MessageRouterResultHandler = new MessageRouterResultHandler(MessageRouter);
MessageLogs = new MessageLogs(connectionString);
}
private IList<string> GetChannelList(string key)
{
IList<string> channelList = null;
string channels = Configuration[key];
if (!string.IsNullOrWhiteSpace(channels))
{
System.Diagnostics.Debug.WriteLine($"Channels by key \"{key}\": {channels}");
string[] channelArray = channels.Split(',');
if (channelArray.Length > 0)
{
channelList = new List<string>();
foreach (string channel in channelArray)
{
channelList.Add(channel.Trim());
}
}
}
else
{
System.Diagnostics.Debug.WriteLine($"No channels defined by key \"{key}\" in app settings");
}
return channelList;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
{
await base.OnTurnAsync(turnContext, cancellationToken);
// Save any state changes that might have occured during the turn.
if (turnContext.Activity.Text!=null && (turnContext.Activity.Text.Contains("watch", StringComparison.CurrentCultureIgnoreCase) || turnContext.Activity.Text.Contains("unwatch", StringComparison.CurrentCultureIgnoreCase)))
{
if (turnContext.Activity.Text.Equals("watch", StringComparison.CurrentCultureIgnoreCase))
{
Command command = new Command(Commands.Watch, null, null);
Activity activity = turnContext.Activity;
await CommandHandler.TakeAgentAction(turnContext, activity, command);
}
if (turnContext.Activity.Text.Equals("unwatch", StringComparison.CurrentCultureIgnoreCase))
{
Command command = new Command(Commands.Unwatch, null, null);
Activity activity = turnContext.Activity;
await CommandHandler.TakeAgentAction(turnContext, activity, command);
}
}
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await UserState.SaveChangesAsync(turnContext, false, cancellationToken);
}
protected virtual Task OnHandoffActivityAsync(ITurnContext<IHandoffActivity> turnContext, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
//protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
//{
// //turnContext.Activity.Text = MaskData(turnContext.Activity.Text);
// await TranscriptStore.LogActivityAsync(turnContext.Activity);
// // Get the state properties from the turn context.
// MessageRouter.StoreConversationReferences(turnContext.Activity);
// AbstractMessageRouterResult messageRouterResult = null;
// bool.TryParse(
// Configuration[KeyRejectConnectionRequestIfNoAggregationChannel],
// out bool rejectConnectionRequestIfNoAggregationChannel);
// var conversationStateAccessors = ConversationState.CreateProperty<ConversationData>(nameof(ConversationData));
// var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());
// var userStateAccessors = UserState.CreateProperty<UserProfile>(nameof(UserProfile));
// var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());
// if (string.IsNullOrEmpty(userProfile.Id))
// {
// // First time around this is set to false, so we will prompt user for name.
// if (conversationData.PromptedUserForId)
// {
// // User userdetails = AuthenticateUser(turnContext.Activity.Text?.Trim());
// // if (userdetails != null)
// // {
// // userProfile.Id = userdetails.Id;
// // userProfile.Name = userdetails.firstName + " " + userdetails.lastName;
// //var thanksMsg = $"Thank you and welcome {userProfile.Name}.";
// userProfile.Id = turnContext.Activity.Text?.Trim();
// var thanksMsg = $"Thank you";
// await turnContext.SendActivityAsync(thanksMsg);
// IActivity activityFromBot = BuildActivity(Guid.NewGuid().ToString(), "Bot", turnContext.Activity.Conversation.Id, thanksMsg);
// await TranscriptStore.LogActivityAsync(activityFromBot);
// turnContext.Activity.Text = "Hello";
// // Reset the flag to allow the bot to go through the cycle again.
// conversationData.PromptedUserForId = false;
// //}
// /*else
// {
// var invalidUserIdMsg = $"Your account validation is failed with given UserId";
// IActivity activityFromBot = BuildActivity(turnContext.Activity.Id, "Bot", turnContext.Activity.Conversation.Id, invalidUserIdMsg);
// await turnContext.SendActivityAsync(activityFromBot);
// await TranscriptStore.LogActivityAsync(activityFromBot);
// conversationData.PromptedUserForId = false;
// await PromptForUserId(turnContext);
// return;
// } */
// }
// else
// {
// await PromptForUserId(turnContext);
// // Set the flag to true, so we don't prompt in the next turn.
// conversationData.PromptedUserForId = true;
// return;
// }
// }
// else if (turnContext.Activity.Text.Equals("Save Transcript", StringComparison.CurrentCultureIgnoreCase))
// {
// StringBuilder transcriptContents = await GetTranscriptContents(turnContext, userProfile);
// byte[] bytes = StringToBytes(transcriptContents.ToString());
// var contentType = "text/plain";
// var attachment = new Attachment
// {
// Name = $"Transcript_{userProfile.Name}.txt",
// ContentUrl = $"data:{contentType};base64,{Convert.ToBase64String(bytes)}",
// ContentType = contentType
// };
// var activity = MessageFactory.Attachment(attachment);
// await turnContext.SendActivityAsync(activity);
// //turnContext.Activity.Text = MaskData(turnContext.Activity.Text);
// // await TranscriptStore.LogActivityAsync(turnContext.Activity);
// return;
// }
// else if (!string.IsNullOrWhiteSpace(turnContext.Activity.Text)
// && (turnContext.Activity.Text.ToLower().Contains("human") || turnContext.Activity.Text.ToLower().Contains("agent")))
// {
// // Let the message router route the activity, if the sender is connected with another user/bot
// messageRouterResult = await MessageRouter.RouteMessageIfSenderIsConnectedAsync(turnContext.Activity);
// if (messageRouterResult is MessageRoutingResult
// && (messageRouterResult as MessageRoutingResult).Type == MessageRoutingResultType.NoActionTaken)
// {
// // Create a connection request on behalf of the sender
// // Note that the returned result must be handled
// //var transcriptContent = await GetTranscriptContents(turnContext, userProfile);
// //turnContext.Activity.Text = transcriptContent.ToString();
// await turnContext.SendActivityAsync($"You have requested transfer to an agent, ConversationId={turnContext.Activity.Conversation.Id}");
// IActivity activity = turnContext.Activity;
// //messageRouterResult = MessageRouter.CreateConnectionRequest(
// //MessageRouter.CreateSenderConversationReference(turnContext.Activity, rejectConnectionRequestIfNoAggregationChannel));
// //messageRouterResult = MessageRouter.CreateConnectionRequest(
// // MessageRouter.CreateSenderConversationReference(activity),
// // rejectConnectionRequestIfNoAggregationChannel);
// if (activity.Type is ActivityTypes.Message)
// {
// if (await CommandHandler.HandleCommandAsync(turnContext) == false)
// {
// // No command detected/handled
// // Let the message router route the activity, if the sender is connected with
// // another user/bot
// messageRouterResult = MessageRouter.CreateConnectionRequest(
// MessageRouter.CreateSenderConversationReference(activity),
// rejectConnectionRequestIfNoAggregationChannel);
// }
// }
// else
// {
// // No action taken - this middleware did not consume the activity so let it propagate
// // await next(ct).ConfigureAwait(false);
// }
// }
// // Handle the result, if necessary
// await MessageRouterResultHandler.HandleResultAsync(messageRouterResult);
// return;
// }
// // Add message details to the conversation data.
// // Convert saved Timestamp to local DateTimeOffset, then to string for display.
// var messageTimeOffset = (DateTimeOffset)turnContext.Activity.Timestamp;
// var localMessageTime = messageTimeOffset.ToLocalTime();
// conversationData.Timestamp = localMessageTime.ToString();
// conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();
// // Run the Dialog with the new message Activity.
// await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
// var dialodAccesser = ConversationState.CreateProperty<DialogState>(nameof(DialogState));
// var dialog = await dialodAccesser.GetAsync(turnContext, () => new DialogState());
// var _dialogSet = new DialogSet(dialodAccesser);
// DialogContext dc = await _dialogSet.CreateContextAsync(turnContext, cancellationToken: cancellationToken);
// var data = dc.ActiveDialog?.State.Values;
// if (data != null)
// {
// await LogTranscriptFromQnAAnswer(turnContext, data);
// }
//}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
//turnContext.Activity.Text = MaskData(turnContext.Activity.Text);
await TranscriptStore.LogActivityAsync(turnContext.Activity);
// Get the state properties from the turn context.
MessageRouter.StoreConversationReferences(turnContext.Activity);
AbstractMessageRouterResult messageRouterResult = null;
bool.TryParse(
Configuration[KeyRejectConnectionRequestIfNoAggregationChannel],
out bool rejectConnectionRequestIfNoAggregationChannel);
var conversationStateAccessors = ConversationState.CreateProperty<ConversationData>(nameof(ConversationData));
var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());
var userStateAccessors = UserState.CreateProperty<UserProfile>(nameof(UserProfile));
var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());
if (string.IsNullOrEmpty(userProfile.Id))
{
// First time around this is set to false, so we will prompt user for name.
if (conversationData.PromptedUserForId)
{
userProfile.Id = turnContext.Activity.Text?.Trim();
var thanksMsg = $"Thank you";
await turnContext.SendActivityAsync(thanksMsg);
IActivity activityFromBot = BuildActivity(Guid.NewGuid().ToString(), "Bot", turnContext.Activity.Conversation.Id, thanksMsg);
await TranscriptStore.LogActivityAsync(activityFromBot);
turnContext.Activity.Text = "Hello";
// Reset the flag to allow the bot to go through the cycle again.
conversationData.PromptedUserForId = false;
//}
}
else
{
await PromptForUserId(turnContext);
// Set the flag to true, so we don't prompt in the next turn.
conversationData.PromptedUserForId = true;
return;
}
}
else if (turnContext.Activity.Text.Equals("Save Transcript", StringComparison.CurrentCultureIgnoreCase))
{
StringBuilder transcriptContents = await GetTranscriptContents(turnContext, userProfile);
byte[] bytes = StringToBytes(transcriptContents.ToString());
var contentType = "text/plain";
var attachment = new Attachment
{
Name = $"Transcript_{userProfile.Name}.txt",
ContentUrl = $"data:{contentType};base64,{Convert.ToBase64String(bytes)}",
ContentType = contentType
};
var activity = MessageFactory.Attachment(attachment);
await turnContext.SendActivityAsync(activity);
return;
}
else if (!string.IsNullOrWhiteSpace(turnContext.Activity.Text)
&& (turnContext.Activity.Text.ToLower().Contains("human") || turnContext.Activity.Text.ToLower().Contains("agent")))
{
// Let the message router route the activity, if the sender is connected with another user/bot
messageRouterResult = await MessageRouter.RouteMessageIfSenderIsConnectedAsync(turnContext.Activity);
if (messageRouterResult is MessageRoutingResult
&& (messageRouterResult as MessageRoutingResult).Type == MessageRoutingResultType.NoActionTaken)
{
await turnContext.SendActivityAsync($"You have requested transfer to an agent, ConversationId={turnContext.Activity.Conversation.Id}");
IActivity activity = turnContext.Activity;
if (activity.Type is ActivityTypes.Message)
{
if (await CommandHandler.HandleCommandAsync(turnContext) == false)
{
messageRouterResult = MessageRouter.CreateConnectionRequest(
MessageRouter.CreateSenderConversationReference(activity),
rejectConnectionRequestIfNoAggregationChannel);
}
}
}
// Handle the result, if necessary
await MessageRouterResultHandler.HandleResultAsync(messageRouterResult);
return;
}
// Add message details to the conversation data.
// Convert saved Timestamp to local DateTimeOffset, then to string for display.
var messageTimeOffset = (DateTimeOffset)turnContext.Activity.Timestamp;
var localMessageTime = messageTimeOffset.ToLocalTime();
conversationData.Timestamp = localMessageTime.ToString();
conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();
// Run the Dialog with the new message Activity.
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
var dialodAccesser = ConversationState.CreateProperty<DialogState>(nameof(DialogState));
var dialog = await dialodAccesser.GetAsync(turnContext, () => new DialogState());
var _dialogSet = new DialogSet(dialodAccesser);
DialogContext dc = await _dialogSet.CreateContextAsync(turnContext, cancellationToken: cancellationToken);
var data = dc.ActiveDialog?.State.Values;
if (data != null)
{
await LogTranscriptFromQnAAnswer(turnContext, data);
}
}
private async Task<StringBuilder> GetTranscriptContents(ITurnContext<IMessageActivity> turnContext, UserProfile userProfile)
{
var transcripts = await TranscriptStore.GetTranscriptActivitiesAsync(turnContext.Activity.ChannelId, turnContext.Activity.Conversation.Id);
var transcriptContents = new StringBuilder();
if (string.IsNullOrEmpty(userProfile.Id))
{
transcriptContents.Append("UserId : " + userProfile.Id);
}
foreach (var transcript in transcripts)
{
transcriptContents.AppendLine(transcript.document.From + "\t:\t" + transcript.document.Text);
}
return transcriptContents;
}
private async Task LogTranscriptFromQnAAnswer(ITurnContext<IMessageActivity> turnContext, ICollection<object> data)
{
foreach (DialogState kv in data)
{
var ds = kv.DialogStack;
var qnaData = ds[0].State;
foreach (var kvPaires in qnaData)
{
if (kvPaires.Key.Equals("values"))
{
var qna = (Dictionary<string, object>)kvPaires.Value;
foreach (var q in qna)
{
if (q.Key.Equals("qnaData"))
{
var ans = (List<QueryResult>)q.Value;
var queryResult = ans[0];
QueryResult qResult = new QueryResult
{
Answer = ans[0].Answer
};
IActivity activity = BuildActivity(Guid.NewGuid().ToString(), "Bot", turnContext.Activity.Conversation.Id, ans[0].Answer);
await TranscriptStore.LogActivityAsync(activity);
}
}
}
}
}
}
private async Task PromptForUserId(ITurnContext<IMessageActivity> turnContext)
{
// Prompt the user for their id.
var verificationMsg = $"For verification purpose can you please type your User ID";
IActivity activityFromBot = BuildActivity(Guid.NewGuid().ToString(), "Bot", turnContext.Activity.Conversation.Id, verificationMsg);
await turnContext.SendActivityAsync(activityFromBot);
await TranscriptStore.LogActivityAsync(activityFromBot);
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
var welcomeText = $"NCI Welcomes You..! Please type in Hello and press ENTER to chat with us. Please do not share any Personally Identifiable Information during the course of this chat.";
IActivity activityFromBot = BuildActivity(Guid.NewGuid().ToString(), "Bot", turnContext.Activity.Conversation.Id, welcomeText);
await turnContext.SendActivityAsync(activityFromBot, cancellationToken);
await TranscriptStore.LogActivityAsync(activityFromBot);
}
}
}
private byte[] StringToBytes(string transcriptToSend)
{
byte[] bytes = new byte[transcriptToSend.Length * sizeof(char)];
System.Buffer.BlockCopy(transcriptToSend.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
private IActivity BuildActivity(string activityId, string from, string conversationId, string text)
{
return new Activity
{
Id = activityId,
From = new ChannelAccount
{
Name = from
},
Conversation = new ConversationAccount
{
Id = conversationId
},
Text = text,
Type = ActivityTypes.Message
};
}
private User AuthenticateUser(string userId)
{
//TODO AS400 User verificaion implemetation should go here
return new User
{
Id = userId,
firstName = "Johny",
lastName = "Depp"
};
}
}
}
使用Microsoft.Bot.Builder;
使用Microsoft.Bot.Builder.AI.QnA;
使用Microsoft.Bot.Builder.Dialogs;
使用Microsoft.Bot.Connector.Authentication;
使用Microsoft.Bot.Schema;
使用Microsoft.Extensions.Configuration;
使用NCIBot;
使用NCIBot.Bots;
使用NCIBot.CommandHandling;
使用NCIBot.ConversationHistory;
使用NCIBot.MessageRouting;
使用制度;
使用System.Collections.Generic;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用下划线.Bot.MessageRouting;
使用下划线.Bot.MessageRouting.DataStore;
使用下划线.Bot.MessageRouting.DataStore.Azure;
使用下划线.Bot.MessageRouting.DataStore.Local;
使用下划线.Bot.MessageRouting.Results;
命名空间Microsoft.BotBuilderSamples.Bots
{
公共类QnABot:ActivityHandler,其中T:Microsoft.Bot.Builder.Dialogs.Dialog
{
受保护的只读BotState会话状态;
受保护的只读Bot.Builder.Dialogs.Dialog对话框;
受保护的只读BotState UserState;
受保护的只读CosmosTranscriptStore转录本存储;
私有常量字符串KeyRejectConnectionRequestIfNoAggregationChannel=“RejectConnectionRequestIfNoAggregationChannel”;
private const string KeyPermittedAggregationChannels=“PermittedAggregationChannels”;
private const string keynodeirectconversationswithchannels=“NoDirectConversationsWithChannels”;
公共IConfiguration配置
{
得到;
保护集;
}
公共消息路由器消息路由器
{
得到;
保护集;
}
public MessageRouterResultHandler MessageRouterResultHandler
{
得到;
保护集;
}
公共命令处理程序命令处理程序
{
得到;
保护集;
}
公共消息日志消息日志
{
得到;
保护集;
}
公共QnABot(会话状态会话状态、用户状态用户状态、T对话框、CosmosTranscriptStore转录本存储、IConfiguration配置)
{
会话状态=会话状态;
UserState=UserState;
对话=对话;
转录存储=转录存储;
string connectionString=“”;//配置[KeyAzureTableStorageConnectionString];
配置=配置;
IRoutingDataStore路由数据存储=null;
if(string.IsNullOrEmpty(connectionString))
{
System.Diagnostics.Debug.WriteLine($”警告!!!找不到连接字符串-使用{nameof(InMemoryRoutingDataStore)}”);
routingDataStore=新的InMemoryRoutingDataStore();
}
其他的
{
System.Diagnostics.Debug.WriteLine($“找到了一个连接字符串-使用{nameof(AzureTableRoutingDataStore)}”);
routingDataStore=新AzureTableRoutingDataStore(connectionString);
}
MessageRouter=新的MessageRouter(
路由数据存储,
新的MicrosoftAppCredentials(配置[“MicrosoftAppId”]、配置[“MicrosoftAppPassword”]);
//MessageRouter.Logger=新的Logging.AggregationChannelLogger(MessageRouter);
ConnectionRequestHandler ConnectionRequestHandler=
新的ConnectionRequestHandler(GetChannelList(KeyNodeDirectConversationswithChannels));
MessageRouterResultHandler=新建MessageRouterResultHandler(MessageRouter);
CommandHandler=新的CommandHandler(
消息路由器,
MessageRouterResultHandler,
connectionRequestHandler,
GetChannelList(KeyPermittedAggregationChannel);
//MessageRouterResultHandler=新建MessageRouterResultHandler(MessageRouter);
MessageLogs=新的MessageLogs(connectionString);
}
私有IList GetChannelList(字符串键)
{
IList channelList=null;
字符串通道=配置[键];
如果(!string.IsNullOrWhiteSpace(通道))
{
System.Diagnostics.Debug.WriteLine($“按键设置的通道\“{key}\”:{Channels}”);
string[]channelArray=channels.Split(',');
如果(channelArray.Length>0)
{
channelList=新列表();
foreach(channelArray中的字符串通道)
{
channelList.Add(channel.Trim());
}
}
}
其他的
{
System.Diagnostics.Debug.WriteLine($“应用程序设置中没有由键\“{key}\”定义的通道”);
}
返回通道列表;
}
公共覆盖异步任务OnTurnAsync(ITurnContext turnContext,CancellationToken CancellationToken=default)
{
wait base.OnTurnAsync(turnContext,cancellationToken);
//保存转弯期间可能发生的任何状态更改。
if(turnContext.Activity.Text!=null&(turnContext.Activity.Text.Contains(“watch”,StringComparison.CurrentCultureIgnoreCase)| | turnContext.Activity.Text.Contains(“unwatch”,StringComparison.CurrentCultureIgnoreCase)))
{
if(turnContext.Activity.Text.Equals(“watch”,StringComparison.CurrentCultureIgnoreCase))
{
指挥部=