You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BotFrameworkAdapter.ProcessActivityAsync手动调用返回null或冻结问题

解决手动调用ProcessActivityAsync返回null或程序冻结的问题

我之前在手动测试Bot Framework的Turn逻辑时也碰到过类似的问题,结合你的EchoBot测试场景,咱们来梳理下问题原因和解决方案:

核心问题分析

你的代码里主要有几个可能导致异常的点:

  • 直接给ProcessActivityAsync传递null作为ClaimsIdentity参数,这会触发adapter内部身份验证逻辑异常,进而导致处理中断或程序冻结
  • 依赖注入初始化时,可能未正确配置adapter的类型或配套服务
  • 控制台环境下异步方法的调用方式不当,容易引发死锁

分步解决方案

1. 正确构造ClaimsIdentity

不要传null,而是创建一个符合Bot Framework要求的身份标识。针对本地测试场景,可以构造包含必要声明的ClaimsIdentity:

var claimsIdentity = new ClaimsIdentity(new List<Claim>
{
    new Claim(ClaimTypes.NameIdentifier, activity.From.Id),
    new Claim(ClaimTypes.Name, activity.From.Name),
    new Claim("http://schemas.microsoft.com/identity/claims/scope", "bot")
}, "Emulator");

2. 确保Adapter类型正确配置

如果依赖注入中注册的IAdapterIntegration实例不符合测试场景,建议直接手动初始化适配的adapter(避免DI配置遗漏):

// 替换DI获取adapter的代码,手动初始化BotFrameworkAdapter
var adapter = new BotFrameworkAdapter(new BotFrameworkAdapterSettings());

3. 避免异步死锁

控制台程序的Main方法若不是async类型,直接使用await可能导致死锁。可以改用GetAwaiter().GetResult()等待异步操作完成,或者将Main改为async Task:

// 示例:使用GetAwaiter().GetResult()避免死锁
var resp = adapter.ProcessActivityAsync(claimsIdentity, activity, bot.OnTurnAsync, CancellationToken.None).GetAwaiter().GetResult();

4. 完整修改后的测试代码

using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Schema;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;

class Program
{
    static void Main(string[] args)
    {
        // 初始化DI容器
        var sc = new ServiceCollection();
        new Startup().ConfigureServices(sc);
        var inject = sc.BuildServiceProvider();

        // 反序列化测试Activity
        var activityJson = @"{
            ""channelData"": {""clientActivityID"": ""15617619894020.cy8e5xuro9h""},
            ""channelId"": ""emulator"",
            ""conversation"": {""id"": ""79e62041-99f6-11e9-a11f-bbd34246e3a4|livechat""},
            ""entities"": [{
                ""requiresBotState"": true,
                ""supportsListening"": true,
                ""supportsTts"": true,
                ""type"": ""ClientCapabilities""
            }],
            ""from"": {""id"": ""5e26d43a-f8ec-485b-9688-091010cb8f88"",""name"": ""User"",""role"": ""user""},
            ""id"": ""918703e0-99f6-11e9-be13-9b4b2092afdf"",
            ""localTimestamp"": ""2019-06-28T19:46:29-03:00"",
            ""locale"": ""en-US"",
            ""recipient"": {""id"": ""12fdf550-99e3-11e9-a11f-bbd34246e3a4"",""name"": ""Bot"",""role"": ""bot""},
            ""serviceUrl"": ""http://localhost:53796"",
            ""text"": ""Ruda"",
            ""textFormat"": ""plain"",
            ""timestamp"": ""2019-06-28T22:46:29.406Z"",
            ""type"": ""message""
        }";
        var activity = JsonConvert.DeserializeObject<Activity>(activityJson);

        // 获取Bot实例
        var bot = inject.GetService<IBot>();

        // 构造合法的ClaimsIdentity
        var claimsIdentity = new ClaimsIdentity(new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, activity.From.Id),
            new Claim(ClaimTypes.Name, activity.From.Name),
            new Claim("http://schemas.microsoft.com/identity/claims/scope", "bot")
        }, "Emulator");

        // 初始化Adapter
        var adapter = new BotFrameworkAdapter(new BotFrameworkAdapterSettings());

        // 添加中间件捕获Bot的回复内容
        adapter.Use(new CatchResponseMiddleware());

        // 处理Activity(避免死锁)
        var resp = adapter.ProcessActivityAsync(claimsIdentity, activity, bot.OnTurnAsync, CancellationToken.None).GetAwaiter().GetResult();

        Console.WriteLine("处理完成,ProcessActivityAsync返回值:" + (resp ?? "null"));
    }
}

// 自定义中间件,用于捕获Bot发送的回复
public class CatchResponseMiddleware : IMiddleware
{
    public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default)
    {
        // 监听SendActivity事件
        turnContext.OnSendActivity(async (ctx, activities, nextSend) =>
        {
            foreach (var activity in activities)
            {
                Console.WriteLine("Bot回复内容:" + activity.Text);
            }
            return await nextSend();
        });

        await next(cancellationToken);
    }
}

额外说明

  • 为什么返回null?BotFrameworkAdapter.ProcessActivityAsync的设计初衷是处理HTTP请求,它的返回值对应HTTP响应而非Bot的对话回复。Bot的回复是通过TurnContext.SendActivityAsync发送的,所以手动调用时返回null是预期行为。
  • 程序冻结的主要原因是异步操作未正确等待,或null的ClaimsIdentity导致adapter内部异步任务无法正常完成。

内容的提问来源于stack exchange,提问作者Rudá Cunha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:55:03