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

如何在Skype Bot的CallingController中获取MessageController的数据?

在Microsoft Bot Framework中关联MessageController与CallingController的会话数据

咱先理清楚核心逻辑:Message和Calling是Skype机器人的两个独立请求通道,但它们共享同一个用户身份和会话上下文。要实现通话时等待用户聊天输入并处理,关键是通过Bot Framework的状态管理机制来跨控制器存储和读取会话状态——比如标记通话是否在等待输入、存储通话会话ID,以及用户输入的值。

下面是具体的实现步骤:

1. 配置状态存储与自定义状态属性

首先得在项目里配置状态服务,同时定义一个自定义类来存储通话相关的会话数据,这样两个控制器都能访问到这些数据。

步骤1.1:定义会话数据类

创建一个简单的类来保存通话状态:

public class CallSessionData
{
    // 标记是否正在等待用户输入
    public bool WaitingForInput { get; set; }
    // 当前活跃的通话会话ID,用来关联具体通话
    public string ActiveCallSessionId { get; set; }
    // 用户输入的字母数字值
    public string UserInputValue { get; set; }
}

步骤1.2:在Startup.cs中注册状态服务

在ConfigureServices方法里添加状态存储和状态属性的注册(开发环境用MemoryStorage,生产建议用Azure Blob/Cosmos DB):

public void ConfigureServices(IServiceCollection services)
{
    // 注册状态存储(开发环境)
    services.AddSingleton<IStorage, MemoryStorage>();
    // 注册用户状态(Skype的用户ID在Message和Calling通道是一致的)
    services.AddSingleton<UserState>();
    // 注册我们自定义的CallSessionData状态属性
    services.AddSingleton<StatePropertyAccessor<CallSessionData>>(sp =>
    {
        var userState = sp.GetService<UserState>();
        return userState.CreateProperty<CallSessionData>("CallSessionData");
    });
}

2. 在CallingController中标记“等待输入”状态

当通话流程走到需要用户输入的环节时,更新会话状态,标记为等待输入,并记录当前通话的会话ID。

示例代码(CallingController中的处理方法):

[Route("api/calling")]
[ApiController]
public class CallingController : ControllerBase
{
    private readonly StatePropertyAccessor<CallSessionData> _callSessionDataAccessor;
    private readonly UserState _userState;

    public CallingController(StatePropertyAccessor<CallSessionData> callSessionDataAccessor, UserState userState)
    {
        _callSessionDataAccessor = callSessionDataAccessor;
        _userState = userState;
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] Activity activity)
    {
        // 处理通话逻辑,比如当需要用户输入时:
        if (activity.Type == ActivityTypes.Call && /* 判断是否走到需要输入的步骤 */)
        {
            var callSessionId = activity.CallId;
            var turnContext = new TurnContext(new BotAdapter(), activity);
            // 获取当前用户的会话数据
            var callSessionData = await _callSessionDataAccessor.GetAsync(turnContext, () => new CallSessionData());
            // 标记为等待输入,记录通话ID
            callSessionData.WaitingForInput = true;
            callSessionData.ActiveCallSessionId = callSessionId;
            // 保存状态
            await _userState.SaveChangesAsync(turnContext);

            // 这里可以向用户发送通话中的提示,比如“请在聊天框输入你的字母数字码”
            // 然后进入等待状态,比如用轮询检查输入是否到达
            await WaitForUserInput(turnContext, callSessionId);
        }

        return Ok();
    }

    // 自定义等待用户输入的方法
    private async Task WaitForUserInput(TurnContext turnContext, string callSessionId)
    {
        while (true)
        {
            await Task.Delay(1000); // 每秒检查一次状态
            var callSessionData = await _callSessionDataAccessor.GetAsync(turnContext, () => new CallSessionData());
            
            // 如果已经收到输入,并且属于当前通话
            if (!callSessionData.WaitingForInput && !string.IsNullOrEmpty(callSessionData.UserInputValue) 
                && callSessionData.ActiveCallSessionId == callSessionId)
            {
                // 执行预设的处理逻辑,比如验证输入、返回通话响应
                await ProcessUserInput(callSessionData.UserInputValue, turnContext);
                // 重置状态
                callSessionData.UserInputValue = null;
                callSessionData.ActiveCallSessionId = null;
                await _userState.SaveChangesAsync(turnContext);
                break;
            }

            // 可选:添加超时逻辑,比如等待5分钟后结束等待
            // if (超时条件) break;
        }
    }

    // 处理用户输入的逻辑
    private async Task ProcessUserInput(string inputValue, TurnContext turnContext)
    {
        // 这里写你的预设逻辑,比如验证格式、返回通话结果
        await turnContext.SendActivityAsync($"收到你的输入:{inputValue},正在处理...");
        // 通话相关的响应处理,比如播放语音提示等
    }
}

3. 在MessageController中接收输入并更新状态

当用户在聊天框发送消息时,检查当前会话是否处于“等待输入”状态,如果是,就保存输入值并标记状态为已完成。

示例代码(MessageController中的Post方法):

[Route("api/messages")]
[ApiController]
public class MessageController : ControllerBase
{
    private readonly StatePropertyAccessor<CallSessionData> _callSessionDataAccessor;
    private readonly UserState _userState;

    public MessageController(StatePropertyAccessor<CallSessionData> callSessionDataAccessor, UserState userState)
    {
        _callSessionDataAccessor = callSessionDataAccessor;
        _userState = userState;
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] Activity activity)
    {
        if (activity.Type == ActivityTypes.Message)
        {
            var turnContext = new TurnContext(new BotAdapter(), activity);
            var callSessionData = await _callSessionDataAccessor.GetAsync(turnContext, () => new CallSessionData());
            
            // 如果当前处于通话等待输入的状态
            if (callSessionData.WaitingForInput)
            {
                // 获取用户输入的字母数字值
                var userInput = activity.Text.Trim();
                // 可以先验证输入格式,比如是否符合字母数字要求
                if (Regex.IsMatch(userInput, @"^[a-zA-Z0-9]+$"))
                {
                    callSessionData.UserInputValue = userInput;
                    callSessionData.WaitingForInput = false;
                    await _userState.SaveChangesAsync(turnContext);
                    await turnContext.SendActivityAsync($"已收到你的输入:{userInput},通话将继续处理");
                }
                else
                {
                    await turnContext.SendActivityAsync("请输入有效的字母数字值");
                }
            }
            else
            {
                // 处理非通话场景的聊天消息
                await turnContext.SendActivityAsync("欢迎使用机器人,请先发起通话操作");
            }
        }

        return Ok();
    }
}

4. 关键注意事项

  • 生产环境状态存储:MemoryStorage只适合开发测试,生产环境一定要用Azure Blob Storage或者Azure Cosmos DB,避免重启机器人后丢失状态数据。
  • 用户ID一致性:Skype的activity.From.Id在Message和Calling通道中是相同的,所以用UserState来存储数据是可靠的。
  • 超时处理:一定要给等待输入的逻辑添加超时机制,避免通话无限期等待用户输入。
  • 并发处理:如果同一个用户可能发起多个通话,要注意用ActiveCallSessionId来区分不同的通话会话,避免数据混乱。

内容的提问来源于stack exchange,提问作者Mainak Chatterjee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:22:46