microsoft / botbuilder-dotnet

Welcome to the Bot Framework SDK for .NET repository, which is the home for the libraries and packages that enable developers to build sophisticated bot applications using .NET.
https://github.com/Microsoft/botframework
MIT License
872 stars 482 forks source link

Webex Adapter do not work with Adaptive Cards - 400 Bad Request #6167

Closed mocalv closed 2 years ago

mocalv commented 2 years ago

Version

SDK 4.12.0

Describe the bug

Using the Webex Adapter for sending messages with a adaptive card causes a 400 Bad Request response by the Webex API.

To Reproduce

Steps to reproduce the behavior:

  1. Open Bot Composer
  2. Create new empty bot
  3. Create "Send a response" Action for "unknown intent" Trigger
  4. Add text and a adaptive card attachment to the action
  5. Install Webex adapter under "package manager"
  6. Configure Webex adapter
  7. Test with ngrok to see the response by webex

Expected behavior

Correct body send to Webex API.

Additional context

Tested Webex API with Postman and Adaptive Cards which works fine.

stevkan commented 2 years ago

@mocalv, I just want to clarify that this is a Composer bot and not a "code-first" SDK bot, yes? You list the SDK version which is why I ask. If this is, in fact, a Composer bot, could you supply the version of Composer that you are using?

In the meantime, I will assume this is a Composer issue and will attempt a repro.

mocalv commented 2 years ago

Correct, I am talking about a Composer bot. Version 2.1.1

mocalv commented 2 years ago

I analysed the traffic with mitmproxy.

My test bot: Bot_Framework_Composer_k1quxvJp7S

POST adaptive card to Webex API: MrAMLUKvL1 rn91eHq1f0

As one can see, Webex sends a 400 bad request back.

With Postman and the Webex documentation, I was able to find the syntax error.

Not working original body:

{
   "attachments":[
      {
        "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
        "body":[
            {
                "isSubtle": false,
                "text": "default text",
                "type": "TextBlock",
                "weight": "bolder"
            }
        ],
        "type":"AdaptiveCard",
        "version":"1.0"
      }
   ],
   "markdown": null,
   "roomId": "[...]",
   "text":"6",
   "toPersonEmail": null,
   "toPersonId": null
}

Working body:

{
   "attachments":[
      {
         "contentType":"application/vnd.microsoft.card.adaptive",
         "content":{
            "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
            "body":[
               {
                  "isSubtle":false,
                  "text":"default text",
                  "type":"TextBlock",
                  "weight":"bolder"
               }
            ],
            "type":"AdaptiveCard",
            "version":"1.0"
         }
      }
   ],
   "markdown": null,
   "roomId": "[...]",
   "text":"6",
   "toPersonEmail": null,
   "toPersonId": null
}

So contentType and content are missing.

According to Azure live metrics, the GeneratorResult do at least log the correct syntax. 2dZGTR90yO

mocalv commented 2 years ago

UPDATE: Even though I liked my idea, I am pretty sure it is wrong because it is working with a "code-first" SDK bot. But I still do not know why it is not working with a composer bot.

UPDATE 2 A debug session for the "code-first" bot shows that the variable attach.Content simply contains the contentType and content again. This is not the case for the composer bot.

Debug "code-first" bot - WebexClientWrapper.cs, line 129 image

Debug composer bot - WebexClientWrapper.cs, line 129 image


Open wrong guess
So the problem seems to be that the method [`CreateMessageWithAttachmentsAsync` only adds `attach.Content`](https://github.com/microsoft/botbuilder-dotnet/blob/6c1c23b90c3e3b983bd5472255a6844707eefdb7/libraries/Adapters/Microsoft.Bot.Builder.Adapters.Webex/WebexClientWrapper.cs#L129). If I look at the method [`CreateAdaptiveCardAttachment`](https://github.com/microsoft/BotBuilder-Samples/blob/901bc140f5aa300fbfa852e64afd7c65fceebff9/samples/csharp_dotnetcore/62.webex-adapter/Bots/EchoBot.cs#L74) within [a bot example](https://github.com/microsoft/BotBuilder-Samples), only the whole attachment object contains the `contentType` and `content` (which contains the adaptive card). CreateMessageWithAttachmentsAsync ```c# public virtual async Task CreateMessageWithAttachmentsAsync(string recipient, string text, IList attachments, MessageTextType messageType = MessageTextType.Text, MessageTarget target = MessageTarget.PersonId, CancellationToken cancellationToken = default) { Message result; var attachmentsContent = new List(); foreach (var attach in attachments) { attachmentsContent.Add(attach.Content); } var request = new WebexMessageRequest { RoomId = target == MessageTarget.SpaceId ? recipient : null, ToPersonId = target == MessageTarget.SpaceId ? null : recipient, Text = text ?? string.Empty, Attachments = attachmentsContent.Count > 0 ? attachmentsContent : null, }; ``` CreateAdaptiveCardAttachment ```c# private static Attachment CreateAdaptiveCardAttachment(string filePath) { var adaptiveCardJson = File.ReadAllText(filePath); var adaptiveCardAttachment = new Attachment() { ContentType = "application/vnd.microsoft.card.adaptive", Content = JsonConvert.DeserializeObject(adaptiveCardJson), }; return adaptiveCardAttachment; } ```
mocalv commented 2 years ago

A simple workaround is to use a dopple structure. The first part is used for e.g. the web chat and the second part is used by Webex.

{
  "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
  "body":[
    {
      "isSubtle":false,
      "text":"default text",
      "type":"TextBlock",
      "weight":"bolder"
    }
  ],
  "type":"AdaptiveCard",
  "version":"1.0",
  "contentType":"application/vnd.microsoft.card.adaptive",
  "content":{
    "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
    "body":[
      {
        "isSubtle":false,
        "text":"default text",
        "type":"TextBlock",
        "weight":"bolder"
      }
    ],
    "type":"AdaptiveCard",
    "version":"1.0"
  }
}
mrivera-ms commented 2 years ago

Thank you for submitting this issue @mocalv. Closing as resolved by the customer.

mocalv commented 2 years ago

@mrivera-ms my provided "solution" is really only a workaroud, since a douple structure is painful to maintain. So please consider reopen it. Maybe it is a Composer issue only, but somewhere this problem should be solved.