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

MS Bot Framework:如何通过Markdown链接传数据并捕获点击事件?

Great question! While you technically can plug custom values into Markdown link URLs (like your [link1](test1) example), this isn’t the right approach for passing data back to your bot. Plain Markdown links are designed to open external web pages, not trigger bot interactions. When a user clicks that test1 link, their chat client will try to navigate to a URL called test1—which won’t exist unless you’ve set up a custom URI handler (something that’s not standard for bot conversations).

Instead, the intended way to create interactive, data-driven "links" is to use Bot Framework Cards. These are built specifically for bot-user interactions and let you attach custom data to buttons that your bot can easily capture.


To detect exactly which action the user took, you’ll use cards with buttons that include a payload (your custom data). When the user clicks the button, the bot receives this payload, so you can identify which link was clicked.

Example 1: Hero Card (Simple Buttons)

Here’s how to replace your Markdown links with a Hero Card that carries your test1/test2 data:

// Build a Hero Card with two interactive buttons
var welcomeCard = new HeroCard
{
    Text = $"Welcome {newMember.Name}!",
    Buttons = new List<CardAction>
    {
        // "ImBack" sends the value back as a message the bot can read
        new CardAction(ActionTypes.ImBack, "Link 1", value: "test1"),
        new CardAction(ActionTypes.ImBack, "Link 2", value: "test2")
    }
};

// Attach the card to your reply message
var reply = MessageFactory.Attachment(welcomeCard.ToAttachment());
await client.Conversations.ReplyToActivityAsync(reply);

Then, in your bot’s message handler, you can check the user’s input to see which button was clicked:

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    var userInput = turnContext.Activity.Text;

    if (userInput == "test1")
    {
        await turnContext.SendActivityAsync("You clicked Link 1! Got your test1 data.", cancellationToken: cancellationToken);
    }
    else if (userInput == "test2")
    {
        await turnContext.SendActivityAsync("You clicked Link 2! Received your test2 data.", cancellationToken: cancellationToken);
    }
    else
    {
        await turnContext.SendActivityAsync("Got your message!", cancellationToken: cancellationToken);
    }
}

Example 2: Adaptive Card (More Customization)

If you need more flexibility (like richer layouts or more complex data), Adaptive Cards are the way to go. You can define them via JSON directly, or use a visual designer to build the layout without writing code. Here’s a quick example:

First, define your Adaptive Card JSON:

{
    "type": "AdaptiveCard",
    "version": "1.0",
    "body": [
        {
            "type": "TextBlock",
            "text": "Welcome {newMember.Name}!",
            "size": "Medium"
        }
    ],
    "actions": [
        {
            "type": "Action.Submit",
            "title": "Link 1",
            "data": {
                "action": "test1",
                "additionalData": "Any extra info you need"
            }
        },
        {
            "type": "Action.Submit",
            "title": "Link 2",
            "data": {
                "action": "test2",
                "additionalData": "More custom data"
            }
        }
    ]
}

Then, attach it to your reply in code:

// Embed the Adaptive Card JSON (you can also load it from a file)
var adaptiveCardJson = $@"
{{
    ""type"": ""AdaptiveCard"",
    ""version"": ""1.0"",
    ""body"": [
        {{
            ""type"": ""TextBlock"",
            ""text"": ""Welcome {newMember.Name}!"",
            ""size"": ""Medium""
        }}
    ],
    ""actions"": [
        {{
            ""type"": ""Action.Submit"",
            ""title"": ""Link 1"",
            ""data"": {{
                ""action"": ""test1""
            }}
        }},
        {{
            ""type"": ""Action.Submit"",
            ""title"": ""Link 2"",
            ""data"": {{
                ""action"": ""test2""
            }}
        }}
    ]
}}";

var adaptiveCard = AttachmentFactory.CreateAdaptiveCardAttachment(adaptiveCardJson);
var reply = MessageFactory.Attachment(adaptiveCard);
await client.Conversations.ReplyToActivityAsync(reply);

To capture the submit action in your bot:

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    // Check if the activity has a payload from an Adaptive Card submit
    if (turnContext.Activity.Value != null)
    {
        // Parse the JSON data into a dynamic object (or a strongly-typed class)
        var actionData = JsonConvert.DeserializeObject<dynamic>(turnContext.Activity.Value.ToString());
        var clickedAction = actionData.action.ToString();

        if (clickedAction == "test1")
        {
            await turnContext.SendActivityAsync("You clicked Link 1 via Adaptive Card!", cancellationToken: cancellationToken);
        }
        else if (clickedAction == "test2")
        {
            await turnContext.SendActivityAsync("You clicked Link 2 via Adaptive Card!", cancellationToken: cancellationToken);
        }
    }
    else
    {
        // Handle regular text messages
        await turnContext.SendActivityAsync("Got your message!", cancellationToken: cancellationToken);
    }
}

Quick Recap

  • Skip plain Markdown links for bot interactions—they’re for external URLs, not data passing.
  • Use Hero Cards for simple button-based interactions, or Adaptive Cards when you need more control over the UI and data.
  • Both card types let you attach custom payloads to buttons, which your bot can easily detect and respond to.

内容的提问来源于stack exchange,提问作者Tony D.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:16:45