Utilisation des modules de tâches dans les robots Microsoft teamsUsing task modules from Microsoft Teams bots

Les modules de tâches peuvent être appelés à partir de robots Microsoft teams à l’aide de boutons sur les cartes adaptatives et les cartes de l’infrastructure bot (connecteur héros, miniature et Office 365).Task modules can be invoked from Microsoft Teams bots using buttons on Adaptive cards and Bot Framework cards (Hero, Thumbnail, and Office 365 Connector). Les modules de tâches sont souvent une meilleure expérience utilisateur que plusieurs étapes de conversation dans lesquelles vous êtes un développeur pour effectuer le suivi de l’état du bot et permettre à l’utilisateur d’interrompre/annuler la séquence.Task modules are often a better user experience than multiple conversation steps where you as a developer have to keep track of bot state and allow the user to interrupt/cancel the sequence.

Il existe deux façons d’appeler des modules de tâches :There are two ways of invoking task modules:

  • Nouveau type de message d’appel task/fetch .A new kind of invoke message task/fetch. À l’aide de l' invoke action de carte pour les fiches de l’infrastructure bot ou de l' Action.Submit action de carte adaptative, avec task/fetch , le module de tâches (une URL ou une carte adaptative) est extrait dynamiquement à partir de votre bot.Using the invoke card action for Bot Framework cards, or the Action.Submit card action for Adaptive cards, with task/fetch, the task module (either a URL or an Adaptive card) is fetched dynamically from your bot.
  • URL de liens détaillés.Deep link URLs. À l’aide de la syntaxe de liens détaillés pour les modules de tâches, vous pouvez utiliser l' openUrl action de carte pour les cartes de l’infrastructure de robots ou l' Action.OpenUrl action de carte pour les cartes adaptatives, respectivement.Using the deep link syntax for task modules, you can use the openUrl card action for Bot Framework cards or the Action.OpenUrl card action for Adaptive cards, respectively. Avec des URL de liens détaillés, l’URL du module de tâche ou le corps de la carte adaptative est évidemment connu à l’avance, ce qui évite d’effectuer un aller-retour de serveur par rapport à task/fetch .With deep link URLs, the task module URL or Adaptive card body is obviously known in advance, avoiding a server round-trip relative to task/fetch.

Important

Pour garantir des communications sécurisées, chaque url et fallbackUrl doit implémenter le protocole de CHIFFREment HTTPS.To ensure secure communications, each url and fallbackUrl must implement the HTTPS encryption protocol.

Appel d’un module de tâches via Task/FetchInvoking a task module via task/fetch

Lorsque l' value objet de l' invoke action de carte ou Action.Submit est initialisé de façon appropriée (expliqué en détail ci-dessous), lorsqu’un utilisateur appuie sur le bouton, un invoke message est envoyé au bot.When the value object of the invoke card action or Action.Submit is initialized in the proper way (explained in more detail below), when a user presses the button an invoke message is sent to the bot. Dans la réponse HTTP au invoke message, un objet TaskInfo est incorporé dans un objet de wrapper, que teams utilise pour afficher le module de tâches.In the HTTP response to the invoke message, there's a TaskInfo object embedded in a wrapper object, which Teams uses to display the task module.

demande/réponse de la tâche/de l’extraction

Examinons chaque étape plus en détail :Let's look at each step in a bit more detail:

  1. Cet exemple illustre une carte héros de bot avec une action de carte « acheter » invoke card action.This example shows a Bot Framework Hero card with a "Buy" invoke card action. La valeur de la type propriété est task/fetch : le reste de l' value objet peut être ce que vous souhaitez.The value of the type property is task/fetch - the rest of the value object can be whatever you like.

  2. Le bot reçoit le invoke message http post.The bot receives the invoke HTTP POST message.

  3. Le bot crée un objet de réponse et le renvoie dans le corps de la réponse POST avec un code de réponse HTTP 200.The bot creates a response object and returns it in the body of the POST response with an HTTP 200 response code. Le schéma des réponses est décrit ci-dessous dans la discussion sur tâche/envoi, mais il est important de se rappeler que le corps de la réponse http contient un objet TaskInfo incorporé dans un objet de wrapper, par exemple :The schema for responses is described below in the discussion on task/submit, but the important thing to remember now is that the body of the HTTP response contains a TaskInfo object embedded in a wrapper object, e.g.:

    {
      "task": {
        "type": "continue",
        "value": {
          "title": "Task module title",
          "height": 500,
          "width": "medium",
          "url": "https://contoso.com/msteams/taskmodules/newcustomer",
          "fallbackUrl": "https://contoso.com/msteams/taskmodules/newcustomer"
        }
      }
    }
    

    L' task/fetch événement et sa réponse pour les robots sont similaires, d’un plan conceptuel, à la microsoftTeams.tasks.startTask() fonction dans le kit de développement logiciel client.The task/fetch event and its response for bots is similar, conceptually, to the microsoftTeams.tasks.startTask() function in the client SDK.

  4. Microsoft teams affiche le module tâches.Microsoft Teams displays the task module.

Envoi du résultat d’un module de tâcheSubmitting the result of a task module

Une fois que l’utilisateur a terminé d’utiliser le module de tâches, le fait de renvoyer le résultat au robot est similaire à celui de la façon dont il fonctionne avec les onglets, mais il existe quelques différences, il est également décrit ici.When the user is finished with the task module, submitting the result back to the bot is similar to the way it works with tabs, but there are a few differences, so it's described here too.

  • HTML/JavaScript ( TaskInfo.url ).HTML/JavaScript (TaskInfo.url). Une fois que vous avez validé ce que l’utilisateur a entré, vous appelez la microsoftTeams.tasks.submitTask() fonction SDK (désignée ci-dessous à des submitTask() fins de lisibilité).Once you've validated what the user has entered, you call the microsoftTeams.tasks.submitTask() SDK function (referred to hereafter as submitTask() for readability purposes). Vous pouvez appeler submitTask() sans aucun paramètre si vous souhaitez simplement que teams ferme le module de tâches, mais la plupart du temps, vous souhaiterez passer un objet ou une chaîne à votre submitHandler .You can call submitTask() without any parameters if you just want Teams to close the task module, but most of the time you'll want to pass an object or a string to your submitHandler. Il suffit de la transmettre en tant que premier paramètre, result .Simply pass it as the first parameter, result. Teams appellera submitHandler : err sera null et sera result l’objet/la chaîne que vous avez transmis submitTask() .Teams will invoke submitHandler: err will be null and result will be the object/string you passed to submitTask(). Si vous appelez submitTask() avec un result paramètre, vous devez transmettre un appId tableau de chaînes ou un tableau appId : cela permet à teams de valider le fait que l’application qui envoie le résultat est la même que celle qui a appelé le module de tâches.If you do call submitTask() with a result parameter, you must pass an appId or an array of appId strings: this allows Teams to validate that the app sending the result is the same one which invoked the task module. Votre bot recevra un task/submit message, result comme décrit ci-dessous.Your bot will receive a task/submit message including result as described below.
  • Carte adaptative ( TaskInfo.card ).Adaptive card (TaskInfo.card). Le corps de la carte adaptative (tel qu’il est rempli par l’utilisateur) est envoyé au robot via un task/submit message lorsque l’utilisateur appuie sur n’importe quel Action.Submit bouton.The Adaptive card body (as filled in by the user) will be sent to the bot via a task/submit message when the user presses any Action.Submit button.

Flexibilité de la tâche/de l’envoiThe flexibility of task/submit

Dans la section précédente, vous avez appris que lorsque l’utilisateur a terminé avec un module de tâche appelé à partir d’un bot, le bot reçoit toujours un task/submit invoke message.In the previous section, you learned that when the user finishes with a task module invoked from a bot, the bot always receives a task/submit invoke message. En tant que développeur, plusieurs options s’offrent à vous lorsque vous répondez au task/submit message :As a developer, you have several options when responding to the task/submit message:

Réponse du corps HTTPHTTP Body Response ScénarioScenario
Aucun (ignorer le task/submit message)None (ignore the task/submit message) La réponse la plus simple n’est pas du tout.The simplest response is no response at all. Votre robot n’est pas tenu de répondre lorsque l’utilisateur a terminé le module de tâches.Your bot is not required to respond when the user is finished with the task module.
{
"task": {
"type": "message",
"value": "Message text"
}
}
Teams affichera la valeur de value dans une boîte de message contextuel.Teams will display the value of value in a popup message box.
{
"task": {
"type": "continue",
"value": <TaskInfo object>
}
}
Vous permet de « chaîner » les séquences de cartes adaptatives dans un Assistant/une expérience en plusieurs étapes.Allows you to "chain" sequences of Adaptive cards together in a wizard/multi-step experience. Notez que le chaînage de cartes adaptatives dans une séquence est un scénario avancé et n’est pas documenté ici. Toutefois, l’exemple d’application Node.js prend en charge cette méthode, mais elle est documentée dans le fichier Readme.MD.Note that chaining Adaptive cards into a sequence is an advanced scenario and not documented here. The Node.js sample app supports it, however, and how it works is documented in its README.md file.

Charge utile des tâches/de l’extraction et des messages de tâches/d’envoiPayload of task/fetch and task/submit messages

Cette section définit le schéma de ce que votre bot reçoit lorsqu’il reçoit task/fetch un task/submit objet infrastructure de bot ou Activity .This section defines the schema of what your bot receives when it receives a task/fetch or task/submit Bot Framework Activity object. Le niveau le plus élevé s’affiche ci-dessous :The important top-level appear below:

PropriétéProperty DescriptionDescription
type Sera toujoursinvokeWill always be invoke
name Soit task/fetch outask/submitEither task/fetch or task/submit
value Charge utile définie par le développeur.The developer-defined payload. En règle générale, la structure de l' value objet reflète ce qui a été envoyé par Teams.Normally the structure of the value object mirrors what was sent from Teams. Dans ce cas, toutefois, il est différent, car nous souhaitons prendre en charge l’extraction dynamique ( task/fetch ) à la fois de l’infrastructure bot ( value ) et des actions de carte adaptative Action.Submit ( data ), et nous avons besoin d’un moyen de communiquer teams context au robot en plus de ce qui a été inclus dans value / data .In this case, however, it's different because we want to support dynamic fetch (task/fetch) from both Bot Framework (value) and Adaptive card Action.Submit actions (data), and we need a way to communicate Teams context to the bot in addition to what was included in value/data.

Pour ce faire, nous combinons les deux dans un objet parent :We do this by combining the two into a parent object:

{
"context": {
"theme": "default" | "dark" | "contrast",
},
"data": [value field from Bot Framework card] | [data field from Adaptive Card]
}

Exemple : réception et réponse aux messages d’appel des tâches/extraction et tâches/envoi-Node.jsExample: Receiving and responding to task/fetch and task/submit invoke messages - Node.js

Notes

L’exemple de code ci-dessous a été modifié entre la version d’évaluation technique et la version finale de cette fonctionnalité : le schéma de la demande a été task/fetch modifié pour suivre ce qui a été documenté dans la section précédente.The sample code below was modified between Technical Preview and final release of this feature: the schema of the task/fetch request changed to follow what was documented in the previous section. Autrement dit, la documentation était correcte, mais l’implémentation ne l’était pas.That is, the documentation was correct but the implementation was not. Consultez les // for Technical Preview [...] commentaires ci-dessous pour en savoir plus sur ce qui a changé.See the // for Technical Preview [...] comments below for what changed.

// Handle requests and responses for a "Custom Form" and an "Adaptive card" task module.
// Assumes request is coming from an Adaptive card Action.Submit button that has a "taskModule" property indicating what to invoke
private async onInvoke(event: builder.IEvent, cb: (err: Error, body: any, status?: number) => void): Promise<void> {
    let invokeType = (event as any).name;
    let invokeValue = (event as any).value;
    if (invokeType === undefined) {
        invokeType = null;
    }
    switch (invokeType) {
        case "task/fetch": {
            if (invokeValue !== undefined && invokeValue.data.taskModule === "customform") { // for Technical Preview, was invokeValue.taskModule
                // Return the specified task module response to the bot
                let fetchTemplate: any = {
                    "task": {
                        "type": "continue",
                        "value": {
                            "title": "Custom Form",
                            "height": 510,
                            "width": 430,
                            "fallbackUrl": "https://contoso.com/teamsapp/customform",
                            "url": "https://contoso.com/teamsapp/customform",
                        }
                    }
                };
                cb(null, fetchTemplate, 200);
            };
            if (invokeValue !== undefined && invokeValue.data.taskModule === "adaptivecard") { // for Technical Preview, was invokeValue.taskModule
                let adaptiveCard = {
                    "type": "AdaptiveCard",
                    "body": [
                        {
                            "type": "TextBlock",
                            "text": "Here is a ninja cat:"
                        },
                        {
                            "type": "Image",
                            "url": "http://adaptivecards.io/content/cats/1.png",
                            "size": "Medium"
                        }
                    ],
                    "version": "1.0"
                };
                // Return the specified task module response to the bot
                let fetchTemplate: any = {
                    "task": {
                        "type": "continue",
                        "value": {
                            "title": "Ninja Cat",
                            "height": "small",
                            "width": "small",
                            "card": {
                                contentType: "application/vnd.microsoft.card.adaptive",
                                content: adaptiveCard,
                            }
                        }
                    }
                };
                cb(null, fetchTemplate, 200);
            };
            break;
        }
        case "task/submit": {
            if (invokeValue.data !== undefined) {
                // It's a valid task module response
                let submitResponse: any = {
                    "task": {
                        "type": "message",
                        "value": "Task complete!",
                    }
                };
                cb(null, fetchTemplates.submitMessageResponse, 200)
            }
        }
    }
}

Voir aussil' exemple de code du module de tâches de Microsoft Teams (NodeJS et robots).See also, Microsoft Teams task module sample code — nodejs and Bot Framework samples.

Exemple : réception et réponse aux messages d’appel des tâches/extraction et tâches/envoi-C #Example: Receiving and responding to task/fetch and task/submit invoke messages - C#

Dans les robots C#, invoke les messages sont traités par un HttpResponseMessage() contrôleur traitant un Activity message.In C# bots, invoke messages are processed by an HttpResponseMessage() controller processing an Activity message. Les task/fetch task/submit requêtes et réponses sont au format JSON.The task/fetch and task/submit requests and responses are JSON. En C#, il n’est pas aussi commode de traiter le JSON brut en Node.js, donc vous avez besoin de classes wrapper pour gérer la sérialisation vers et à partir de JSON.In C#, it's not as convenient to deal with raw JSON as it is in Node.js, so you need wrapper classes to handle the serialization to and from JSON. Il n’existe pas encore de prise en charge directe de cette fonction dans le Kit de développement logiciel (SDK) c# de Microsoft Teams, mais vous pouvez voir un exemple de ce à quoi ressembleront ces classes wrapper simples dans l' exemple d’application c#.There's no direct support for this in the Microsoft Teams C# SDK yet, but you can see an example of what these simple wrapper classes would look like in the C# sample app.

Vous trouverez ci-dessous un exemple de code en C# pour task/fetch la gestion et les task/submit messages qui utilisent ces classes wrapper ( TaskInfo , TaskEnvelope ), extraits de l' exemple:Below is example code in C# for handling task/fetch and task/submit messages using these wrapper classes (TaskInfo, TaskEnvelope), excerpted from the sample:

private HttpResponseMessage HandleInvokeMessages(Activity activity)
{
    var activityValue = activity.Value.ToString();
    if (activity.Name == "task/fetch")
    {
        var action = Newtonsoft.Json.JsonConvert.DeserializeObject<Models.BotFrameworkCardValue<string>>(activityValue);

        Models.TaskInfo taskInfo = GetTaskInfo(action.Data);
        Models.TaskEnvelope taskEnvelope = new Models.TaskEnvelope
        {
            Task = new Models.Task()
            {
                Type = Models.TaskType.Continue,
                TaskInfo = taskInfo
            }
        };
        return Request.CreateResponse(HttpStatusCode.OK, taskEnvelope);
    }
    else if (activity.Name == "task/submit")
    {
        ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
        Activity reply = activity.CreateReply("Received = " + activity.Value.ToString());
        connector.Conversations.ReplyToActivity(reply);
    }
    return new HttpResponseMessage(HttpStatusCode.Accepted);
}

// Helper function for building the TaskInfo object based on the incoming request
private static Models.TaskInfo GetTaskInfo(string actionInfo)
{
    Models.TaskInfo taskInfo = new Models.TaskInfo();
    switch (actionInfo)
    {
        case TaskModuleIds.YouTube:
            taskInfo.Url = taskInfo.FallbackUrl = ApplicationSettings.BaseUrl + "/" + TaskModuleIds.YouTube;
            SetTaskInfo(taskInfo, TaskModuleUIConstants.YouTube);
            break;
        case TaskModuleIds.PowerApp:
            taskInfo.Url = taskInfo.FallbackUrl = ApplicationSettings.BaseUrl + "/" + TaskModuleIds.PowerApp;
            SetTaskInfo(taskInfo, TaskModuleUIConstants.PowerApp);
            break;
        case TaskModuleIds.CustomForm:
            taskInfo.Url = taskInfo.FallbackUrl = ApplicationSettings.BaseUrl + "/" + TaskModuleIds.CustomForm;
            SetTaskInfo(taskInfo, TaskModuleUIConstants.CustomForm);
            break;
        case TaskModuleIds.AdaptiveCard:
            taskInfo.Card = AdaptiveCardHelper.GetAdaptiveCard();
            SetTaskInfo(taskInfo, TaskModuleUIConstants.AdaptiveCard);
            break;
        default:
            break;
    }
    return taskInfo;
}

L’exemple ci-dessus ne montre pas la SetTaskInfo() fonction qui définit les height width Propriétés, et title de l' TaskInfo objet pour chaque cas.Not shown in the above example is the SetTaskInfo() function, which sets the height, width, and title properties of the TaskInfo object for each case. Voici le code source pour SetTaskInfo ().Here's the source code for SetTaskInfo().

Actions de carte d’infrastructure bot et action de carte adaptative. soumettre des actionsBot Framework card actions vs. Adaptive card Action.Submit actions

Le schéma des actions de carte de l’infrastructure de robots est légèrement différent des actions de carte adaptative Action.Submit .The schema for Bot Framework card actions is slightly different from Adaptive card Action.Submit actions. Par conséquent, le mode d’appel des modules de tâches est légèrement différent : l' data objet dans Action.Submit contient un msteams objet de sorte qu’il ne gêne pas les autres propriétés de la carte.As a result, the way to invoke task modules is slightly different too: the data object in Action.Submit contains an msteams object so it won't interfere with other properties in the card. Le tableau suivant montre un exemple de chacun :The following table shows an example of each:

Action de carte de l’infrastructure botBot Framework card action Action de carte adaptative. action d’envoiAdaptive card Action.Submit action
{
"type": "invoke",
"title": "Buy",
"value": {
"type": "task/fetch",
<...>
}
}
{
"type": "Action.Submit",
"id": "btnBuy",
"title": "Buy",
"data": {
<...>,
"msteams": {
"type": "task/fetch"
}
}
}