C# Bot Framework v4.2-从OnTurnError异常完全恢复

C# Bot Framework v4.2-从OnTurnError异常完全恢复,c#,.net,error-handling,botframework,C#,.net,Error Handling,Botframework,我一直在阅读文档,查看代码示例以获得提示和灵感,但到目前为止,我什么也没找到 如果我们捕捉到机器人程序中发生的全局异常,我们将输入OnTurnError处理程序: // Catches any errors that occur during a conversation turn and logs them. options.OnTurnError = async (context, exception) => { logger.LogError($"Exception caug

我一直在阅读文档,查看代码示例以获得提示和灵感,但到目前为止,我什么也没找到

如果我们捕捉到机器人程序中发生的全局异常,我们将输入
OnTurnError
处理程序:

// Catches any errors that occur during a conversation turn and logs them.
options.OnTurnError = async (context, exception) =>
{
    logger.LogError($"Exception caught : {exception}");
    await context.SendActivityAsync("Sorry, it looks like something went wrong.");
};
我在文档或任何讨论中都没有发现任何人随后正在从错误中恢复并重新启动对话的内容。我有一个可行的解决方案,但我想知道我是否错过了一个更“最佳实践”的方法。我现在正在做这件事:

options.OnTurnError = async (context, exception) =>
{
    logger.LogError($"Exception caught : {exception}");
    await context.SendActivityAsync("Sorry, it looks like something went wrong.");

    await _conversationState.DeleteAsync(context);

    await MyBot.SendIntroCardAsync(context, CancellationToken.None);
};
如果没有像这样的恢复,我们会让用户陷入死对话。我没有找到更好的解决方案吗?

“擦除”会话状态并重新开始当然是处理它的一种方法,尽管有点笨手笨脚。调用
deleteAscync
是正确的方法。也许你认为你不想抹去所有的对话状态,也许只是擦掉<代码>对话状态< /代码>?您只需调用
IStatePropertyAccessor::DeleteAsync
。这一切都取决于你在州里维持什么,以及在哪里

现在,我发现一个问题是试图从
OnTurnError
处理程序触发bot,以便在发生这种情况时立即重新启动对话。看起来您正在调用一个静态方法(
sendinrocardasync
),我想这是可行的,但它创建了一些非常紧密的耦合,这让我感到不舒服

我的部分想法是,如果您的
MyBot
真的想参与到这一级别的异常处理中,然后可能会将一个实际的
try
/
catch
放入bot本身的
OnTurnAsync
,该bot本身基本上将活动方的处理保持在其职责范围内,并且能够干净地包含和触发
sendinrocardaync
。然后,在这种情况下,除非bot无法正确处理异常,否则很可能永远不会命中
OnTurnError
。除了调用
SendIntroCardAsync
,我仍然会保留处理程序逻辑中的所有内容,但现在您知道,只有在机器人无法正确处理异常(这应该是极为罕见的)或上游中间件抛出异常的情况下,才会触发该异常。我也不太喜欢这个,因为它给机器人带来了一种不可知的责任

我认为,考虑到这一点,我可能会采用的最后一种方法是构建一个特定的中间件,我将在管道的“顶部”安装该中间件,该中间件执行顶级异常处理,而不是在完成该处理后确切地知道调用什么,实际上,它只是在可配置的次数内重新执行整个管道。这样,从顶级异常处理的角度来看,您的下游中间件和bot仍然是“哑巴”的,但您仍然可以通过在注册时使用此中间件配置回调来选择要做什么(在您的情况下是擦除某些状态),最终,一旦异常作为新请求处理,您的机器人将看到回合的重播。这个中间件甚至可以向
iTunesContext::TurnState
包中添加一些东西,让下游逻辑检测到它处于重播状态,并且行为略有不同。例如,假设您的机器人能够做到这一点:

public async Task OnTurnAsync(ITurnContext turnContext,CancellationToken CancellationToken=default(CancellationToken))
{
if(turnContext.IsReplayingTurnBecauseOfException())
{
…发送抱歉消息并从任何您想要的位置重新启动对话框。。。
}
}
其中,
isreplayingturnbecuseofeexception
(命名供讨论)是
iTunesContext
的一种扩展方法,它将与这一新的中间件一起提供,用于直接从读取
TurnState
详细信息中提取代码。比如:

public static bool正在播放TurnBecauseOfeException(此iTunesContext turnContext)=>
turnContext.TurnState.ContainsKey(“MySuperAwesomeExceptionHandlingMiddleware.isreplaying BecauseofeException”);

我同意你的观点。特别是紧耦合。我从来没有写过机器人,我已经开始了一个非常复杂的一个重大项目。。。让我放松一下:)我将仔细考虑一下你的重播概念。使用管道是很有意义的。我可能会将这个确切的功能添加到我正在开发的扩展库中。当我这样做的时候,我会确保回来并用链接更新这个答案。请这样做,它听起来非常有用,非常需要。另一个需要更多讨论的问题(我知道这与原始问题相切)是在
Dialog
s中正确使用DI。必须“提前使用”构建
对话框集有点令人沮丧,并且使DI的正确使用有点尴尬。除非你在这个主题上也有一些不错的阅读链接?@DrewMarsh扩展库有什么更新吗?:)