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

如何将用户上下文详情从Bot控制器传递至FormDialog(.NET环境)

如何将用户上下文详情从机器人控制器传递到FormDialog?

嘿,我来帮你搞定这个问题!在.NET Bot Framework环境下,要把控制器里的用户上下文(比如Activity中的用户信息、对话数据)传递到FormDialog,核心思路是借助Bot的状态管理机制(UserState/ConversationState)暂存数据,再在FormDialog里读取使用。下面是具体的实现步骤和代码示例:

步骤1:先配置状态存储(如果还没做)

首先得确保你的Bot已经配置了状态存储,Azure Bot Service默认支持Azure Blob或Cosmos DB作为持久化存储,本地开发可以先用MemoryStorage过渡。在Startup.cs里注册状态服务:

public void ConfigureServices(IServiceCollection services)
{
    services.AddBot<YourBotClass>(options =>
    {
        // 配置状态存储(生产环境建议替换为AzureBlobStorage或CosmosDbStorage)
        IStorage dataStore = new MemoryStorage();
        var conversationState = new ConversationState(dataStore);
        var userState = new UserState(dataStore);

        options.State.Add(conversationState);
        options.State.Add(userState);
    });
}

步骤2:在控制器中存储用户上下文

在你的Post控制器里,把Activity里的关键上下文信息(比如用户ID、自定义字段、对话ID等)存入ConversationState或UserState:

private readonly IServiceProvider _serviceProvider;

// 通过构造函数注入服务提供者
public YourBotController(IServiceProvider serviceProvider)
{
    _serviceProvider = serviceProvider;
}

public virtual async Task<HttpResponseMessage> Post([FromBody] Activity activity)
{
    if (activity != null && activity.GetActivityType() == ActivityTypes.Message)
    {
        // 获取状态服务实例
        var conversationState = _serviceProvider.GetService<ConversationState>();
        var userState = _serviceProvider.GetService<UserState>();

        // 创建状态属性容器,用于存储上下文
        var conversationProps = conversationState.CreateProperty<ConversationContext>("ConversationContext");
        var userProps = userState.CreateProperty<UserContext>("UserContext");

        // 读取或初始化上下文对象,存入需要的信息
        var conversationContext = await conversationProps.GetAsync(activity.Context, () => new ConversationContext());
        conversationContext.UserId = activity.From.Id;
        conversationContext.SourceChannel = activity.ChannelId;
        conversationContext.LastUserMessage = activity.Text;

        // 保存状态变更
        await conversationState.SaveChangesAsync(activity.Context, false);

        // 启动对话链,传递状态服务到RootDialog
        await Conversation.SendAsync(activity, () => new RootDialog(conversationState, userState));
    }
    else
    {
        HandleSystemMessage(activity);
    }
    return new HttpResponseMessage(HttpStatusCode.Accepted);
}

// 自定义上下文模型类,按需添加字段
public class ConversationContext
{
    public string UserId { get; set; }
    public string SourceChannel { get; set; }
    public string LastUserMessage { get; set; }
}

public class UserContext
{
    // 用于存储跨会话的用户持久化信息,比如偏好、历史记录等
}

步骤3:在RootDialog中接收状态并传递给FormDialog

创建RootDialog,在构造函数中接收状态服务,然后在对话启动时读取上下文,再初始化FormDialog:

public class RootDialog : IDialog<object>
{
    private readonly ConversationState _conversationState;
    private readonly UserState _userState;

    public RootDialog(ConversationState conversationState, UserState userState)
    {
        _conversationState = conversationState;
        _userState = userState;
    }

    public async Task StartAsync(IDialogContext context)
    {
        // 读取之前存储的会话上下文
        var conversationProps = _conversationState.CreateProperty<ConversationContext>("ConversationContext");
        var conversationContext = await conversationProps.GetAsync(context.Context, () => new ConversationContext());

        // 初始化FormDialog时,把上下文传递给FormBuilder
        var formDialog = FormDialog.FromForm(() => RequestOrder.BuildEnquiryForm(conversationContext), FormOptions.PromptInStart);
        context.Call(formDialog, ResumeAfterFormDialog);
    }

    private async Task ResumeAfterFormDialog(IDialogContext context, IAwaitable<RequestOrder> result)
    {
        // 处理FormDialog返回的表单结果
        var requestOrder = await result;
        await context.PostAsync($"已收到你的咨询:【类型】{requestOrder.EnquiryType},【详情】{requestOrder.EnquiryDetails}");
        context.Wait(MessageReceivedAsync);
    }

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var message = await result;
        await context.PostAsync("你可以继续发起新的咨询,或者输入「结束」终止对话");
        context.Wait(MessageReceivedAsync);
    }
}

步骤4:在FormBuilder中使用上下文数据

修改你的RequestOrder.BuildEnquiryForm方法,接收上下文参数,然后在表单字段中动态使用这些数据(比如设置默认值、个性化提示语):

public class RequestOrder
{
    public string EnquiryType { get; set; }
    public string EnquiryDetails { get; set; }

    // 接收上下文参数,构建个性化表单
    public static IForm<RequestOrder> BuildEnquiryForm(ConversationContext conversationContext)
    {
        return new FormBuilder<RequestOrder>()
            .Field(nameof(EnquiryType), 
                prompt: $"你好 {conversationContext.UserId}(来自{conversationContext.SourceChannel}渠道),请选择咨询类型:",
                defaultValue: "技术支持") // 可以从上下文读取默认值
            .Field(nameof(EnquiryDetails), 
                prompt: "请详细描述你的问题:",
                validate: async (state, value) =>
                {
                    // 也可以用上下文做自定义校验逻辑
                    var details = value as string;
                    if (string.IsNullOrEmpty(details))
                    {
                        return new ValidateResult { IsValid = false, Feedback = "请输入有效的咨询详情哦" };
                    }
                    return new ValidateResult { IsValid = true };
                })
            .Build();
    }
}

临时传递的替代方案(无需持久化)

如果只是临时传递上下文,不需要跨会话保存,可以直接用DialogContext的PrivateConversationData存储数据:

在控制器里:

await Conversation.SendAsync(activity, () =>
{
    return Chain.From(() =>
    {
        var currentContext = DialogContext.CurrentContext;
        // 把临时数据存入会话私有存储
        currentContext.PrivateConversationData.SetValue("UserId", activity.From.Id);
        currentContext.PrivateConversationData.SetValue("LastMessage", activity.Text);
        return FormDialog.FromForm(RequestOrder.BuildTemporaryForm);
    });
});

在FormBuilder里读取:

public static IForm<RequestOrder> BuildTemporaryForm()
{
    return new FormBuilder<RequestOrder>()
        .Field(nameof(RequestOrder.EnquiryType), 
            async (state) =>
            {
                var currentContext = DialogContext.CurrentContext;
                string userId = currentContext.PrivateConversationData.GetValue<string>("UserId");
                return new ValidateResult { Prompt = $"你好 {userId},请选择咨询类型:" };
            })
        .Field(nameof(RequestOrder.EnquiryDetails))
        .Build();
}

注意:PrivateConversationData仅在当前会话有效,会话结束后数据会丢失,适合临时传递场景;而UserState/ConversationState是持久化存储,适合跨会话保留用户信息。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:07:10