【发布时间】:2019-02-15 12:15:55
【问题描述】:
我正在使用 Bot Framework SDK v-4。我创建了几个继承自ComponentDialog 的对话框并覆盖了方法:BeginDialogAsync 和ContinueDialogAsync。下面是IBot的实现。
public class Bot : IBot
{
private readonly BotAccessors _accessors;
private readonly ILogger _logger;
private DialogSet _dialogs = null;
private string _botName = string.Empty;
private IConfiguration _configuration = null;
private UserDetail _userDetail = null;
private ConversationData _conversationData = null;
private IStatePropertyAccessor<TurnState> _turnStateAccessor = null;
/// <summary>
/// Initializes a new instance of the class.
/// </summary>
public Bot(BotAccessors accessors, ILoggerFactory loggerFactory, IConfiguration configuration)
{
_accessors = accessors ?? throw new System.ArgumentNullException(nameof(accessors));
if (loggerFactory == null)
{
throw new System.ArgumentNullException(nameof(loggerFactory));
}
_configuration = configuration;
_dialogs = new DialogSet(accessors.ConversationState.CreateProperty<DialogState>(nameof(DialogState)));
_turnStateAccessor = accessors.TurnStateAccessor;
_dialogs.Add(new GreetingDialog(_turnStateAccessor, loggerFactory, configuration));
_dialogs.Add(new QnADialog(_turnStateAccessor, loggerFactory, configuration));
_botName = configuration["BotName"];
_logger = loggerFactory.CreateLogger<Bot>();
_logger.LogTrace("Bot turn start.");
}
public override Task<DialogTurnResult> BeginDialogAsync(DialogContext outerDc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{
_turnState = _turnStateAccessor.GetAsync(outerDc.Context).Result;
outerDc.ContinueDialogAsync();
return base.BeginDialogAsync(outerDc, options, cancellationToken);
}
public override Task<DialogTurnResult> ContinueDialogAsync(DialogContext outerDc, CancellationToken cancellationToken = default(CancellationToken))
{
_turnState = _turnStateAccessor.GetAsync(outerDc.Context).Result;
//some code
_turnStateAccessor.SetAsync(outerDc.Context, _turnState).ConfigureAwait(false);
return base.ContinueDialogAsync(outerDc, cancellationToken);
}
}
我从 Bot 的 OnTurnAsync 方法调用对话框,如下所示:await dialogContext.BeginDialogAsync(nameof(GreetingDialog)).ConfigureAwait(false);。它到达我的对话框的BeginDialogAsync 方法,然后继续到ContinueDialogAsync。它工作正常,但是,当从该方法返回(使用base.ContinueDialogAsync(outerDc, cancellationToken);)时,我得到了一些我从 Visual Studio 的诊断工具中捕获的异常。
另外,我将异常作为活动消息发送到客户端(机器人框架模拟器),如下所示。
抱歉,好像出了点问题。例外: System.ArgumentNullException:值不能为空。参数名称: 对话框 ID 在 Microsoft.Bot.Builder.Dialogs.DialogContext.BeginDialogAsync(字符串 dialogId, 对象选项, CancellationToken cancelToken) in D:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\DialogContext.cs:line 84 在 Microsoft.Bot.Builder.Dialogs.ComponentDialog.BeginDialogAsync(DialogContext outerDc, 对象选项, CancellationToken cancelToken) in D:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\ComponentDialog.cs:line 59 在 Microsoft.Bot.Builder.Dialogs.DialogContext.BeginDialogAsync(字符串 dialogId, 对象选项, CancellationToken cancelToken) in D:\a\1\s\libraries\Microsoft.Bot.Builder.Dialogs\DialogContext.cs:line 84 在 Chatbot.Bot.OnTurnAsync(ITurnContext turnContext, CancellationToken 取消令牌)在 C:\GIS\ChatbotNew\Chatbot\Chatbot\Bot.cs:第 120 行 Microsoft.Bot.Builder.MiddlewareSet.ReceiveActivityWithStatusAsync(ITurnContext turnContext、BotCallbackHandler 回调、CancellationToken 取消令牌)在 D:\a\1\s\libraries\Microsoft.Bot.Builder\MiddlewareSet.cs:第 55 行 Microsoft.Bot.Builder.BotAdapter.RunPipelineAsync(ITurnContext turnContext、BotCallbackHandler 回调、CancellationToken 取消令牌)在 D:\a\1\s\libraries\Microsoft.Bot.Builder\BotAdapter.cs:167 行
Update-1
根据 Drew 的回答,我删除了 outerDc.ContinueDialogAsync();,但在单步执行 BeginDialogAsync 函数中的 return base.BeginDialogAsync(outerDc, options, cancellationToken); 时出现了一些错误(如下所示)。
另外,在单步执行OnTurnAsync 函数时,我在尝试获取BotState 时遇到错误,如下所示。
TurnState 实现:
public class TurnState
{
public int TurnCount { get; set; } = 0;
public string BotType { get; set; } = string.Empty;
public string ConversationLanguage { get; set; } = string.Empty;
//other properties...
}
在尝试创建 DialogContext 时也出现类似错误。
ConfigureServices 在 Startup.cs 中:
public void ConfigureServices(IServiceCollection services)
{
services.AddBot<Bot>(options =>
{
var secretKey = Configuration.GetSection("botFileSecret")?.Value;
// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
var botConfig = BotConfiguration.Load(@".\Chatbot.bot", secretKey);
services.AddSingleton(sp => botConfig);
// Retrieve current endpoint.
var service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == "development").FirstOrDefault();
if (!(service is EndpointService endpointService))
{
throw new InvalidOperationException($"The .bot file does not contain a development endpoint.");
}
//options.CredentialProvider = new SimpleCredentialProvider(Configuration[MicrosoftAppCredentials.MicrosoftAppIdKey], Configuration[MicrosoftAppCredentials.MicrosoftAppPasswordKey]);
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
// Creates a logger for the application
ILogger logger = _loggerFactory.CreateLogger<Bot>();
// Catches any errors that occur during a conversation turn and logs them.
options.OnTurnError = async (context, exception) =>
{
await context.SendActivityAsync("Sorry, it looks like something went wrong. Exception: " + exception);
};
// The Memory Storage used here is for local bot debugging only. When the bot
// is restarted, everything stored in memory will be gone.
IStorage dataStore = new MemoryStorage();
var conversationState = new ConversationState(dataStore);
options.State.Add(conversationState);
});
// Create and register state accesssors.
// Acessors created here are passed into the IBot-derived class on every turn.
services.AddSingleton<BotAccessors>(sp =>
{
var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
if (options == null)
{
throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the state accessors");
}
var conversationState = options.State.OfType<ConversationState>().FirstOrDefault();
if (conversationState == null)
{
throw new InvalidOperationException("ConversationState must be defined and added before adding conversation-scoped state accessors.");
}
// Create the custom state accessor.
// State accessors enable other components to read and write individual properties of state.
var accessors = new BotAccessors(conversationState)
{
TurnStateAccessor = conversationState.CreateProperty<TurnState>(BotAccessors.TurnStateName),
};
return accessors;
});
}
有什么帮助吗?
【问题讨论】:
标签: c# botframework azure-bot-service