Verwenden von Aufgaben Modulen von Microsoft Teams-BotsUsing task modules from Microsoft Teams bots

Aufgaben Module können von Microsoft Teams-Bots mithilfe von Schaltflächen auf adaptiven Karten und bot-Framework-Karten (Hero, Thumbnail und Office 365-Konnektor) aufgerufen werden.Task modules can be invoked from Microsoft Teams bots using buttons on Adaptive cards and Bot Framework cards (Hero, Thumbnail, and Office 365 Connector). Aufgaben Module sind häufig eine bessere Benutzeroberfläche als mehrere Unterhaltungs Schritte, bei denen Sie als Entwickler den Status von bot überwachen und dem Benutzer die Unterbrechung/Absage der Sequenz ermöglichen müssen.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.

Es gibt zwei Möglichkeiten zum Aufrufen von Aufgaben Modulen:There are two ways of invoking task modules:

  • Eine neue Art von Invoke task/fetch -Nachricht.A new kind of invoke message task/fetch. Wenn Sie die Karten invoke Aktion für bot-Framework-Karten verwenden oder die Karten Action.Submit Aktion für Adaptive Karten mit task/fetch , wird das Aufgabenmodul (entweder eine URL oder eine Adaptive Karte) dynamisch von Ihrem bot abgerufen.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.
  • Deep Link-URLs.Deep link URLs. Mithilfe der Deep Link-Syntax für Aufgaben Modulekönnen Sie die Karten openUrl Aktion für bot-frameworkkarten oder die Action.OpenUrl Karten Aktion für Adaptive Karten verwenden.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. Bei Deep Link-URLs ist die URL des Aufgabenmoduls oder der Adaptive Kartentext offensichtlich vorab bekannt, sodass ein Server-Roundtrip relativ zu vermieden wird 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.

Wichtig

Um die sichere Kommunikation sicherzustellen url , fallbackUrl müssen Sie das HTTPS-Verschlüsselungsprotokoll implementieren.To ensure secure communications, each url and fallbackUrl must implement the HTTPS encryption protocol.

Aufrufen eines Aufgabenmoduls über Task/FETCHInvoking a task module via task/fetch

Wenn das value Objekt der invoke Karte Action.Submit auf ordnungsgemäße Weise initialisiert wird (im folgenden näher erläutert), wird beim Drücken der Schaltfläche eine invoke Nachricht an den bot gesendet.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. In der HTTP-Antwort auf die invoke Nachricht gibt es ein taskinfo-Objekt , das in ein Wrapperobjekt eingebettet ist, das die Teams zum Anzeigen des Aufgabenmoduls verwenden.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.

Aufgabe/Abrufanforderung/Antwort

Lassen Sie uns die einzelnen Schritte etwas ausführlicher betrachten:Let's look at each step in a bit more detail:

  1. In diesem Beispiel wird eine Hero-Karte für bot-Frameworks mit einer "Buy" invoke - Karten Aktiongezeigt.This example shows a Bot Framework Hero card with a "Buy" invoke card action. Der Wert der type Eigenschaft ist task/fetch -der Rest des value Objekts kann sein, was Sie möchten.The value of the type property is task/fetch - the rest of the value object can be whatever you like.

  2. Der bot erhält die invoke http-Post-Nachricht.The bot receives the invoke HTTP POST message.

  3. Der bot erstellt ein Response-Objekt und gibt es im Text der Post-Antwort mit einem HTTP 200-Antwortcode zurück.The bot creates a response object and returns it in the body of the POST response with an HTTP 200 response code. Das Schema für Antworten wird im folgenden in der Diskussion über Aufgabe/Submitbeschrieben, aber wichtig ist jetzt, dass der Text der HTTP-Antwort ein taskinfo-Objekt enthält, das in ein Wrapperobjekt eingebettet ist, beispielsweise: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"
        }
      }
    }
    

    Das task/fetch Ereignis und seine Antwort auf Bots ähneln konzeptuell der microsoftTeams.tasks.startTask() Funktion im Client-SDK.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 zeigt den Aufgabenmodul an.Microsoft Teams displays the task module.

Übermitteln des Ergebnisses eines AufgabenmodulsSubmitting the result of a task module

Wenn der Benutzer mit dem Aufgabenmodul fertig ist, ist das Senden des Ergebnisses zurück an den bot ähnlich wie bei Registerkarten, es gibt jedoch einige Unterschiede, die daher auch hier beschrieben werden.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). Nachdem Sie überprüft haben, was der Benutzer eingegeben hat, rufen Sie die microsoftTeams.tasks.submitTask() SDK-Funktion auf (wird im folgenden als submitTask() Zweck der Lesbarkeit bezeichnet).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). Sie können submitTask() ohne Parameter aufrufen, wenn Sie lediglich möchten, dass Teams den Aufgabenmodul schließen, aber in den meisten Fällen möchten Sie ein Objekt oder eine Zeichenfolge an Ihren übergeben 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. Übergeben Sie es einfach als ersten Parameter, result .Simply pass it as the first parameter, result. Teams werden aufgerufen submitHandler : err wird null und ist result das Objekt/die Zeichenfolge, die Sie an übergeben haben submitTask() .Teams will invoke submitHandler: err will be null and result will be the object/string you passed to submitTask(). Wenn Sie submitTask() einen result Parameter aufrufen, müssen Sie ein appId oder ein Array von appId Zeichenfolgen übergeben: Dadurch können Teams überprüfen, ob die APP, die das Ergebnis sendet, dieselbe ist, die das Aufgabenmodul aufgerufen hat.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. Ihr bot erhält eine task/submit Nachricht result wie untenbeschrieben.Your bot will receive a task/submit message including result as described below.
  • Adaptive Karte ( TaskInfo.card ).Adaptive card (TaskInfo.card). Der Adaptive Kartentext (wie vom Benutzer ausgefüllt) wird über eine Nachricht an den bot gesendet, task/submit Wenn der Benutzer eine beliebige Action.Submit Schaltfläche drückt.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ät von Task/SubmitThe flexibility of task/submit

Im vorherigen Abschnitt haben Sie gelernt, dass der bot immer eine Nachricht erhält, wenn der Benutzer mit einem Aufgabenmodul endet, das von einem bot aufgerufen wird task/submit invoke .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. Als Entwickler haben Sie mehrere Möglichkeiten, wenn Sie auf die Nachricht reagieren task/submit :As a developer, you have several options when responding to the task/submit message:

HTTP-Text AntwortHTTP Body Response SzenarioScenario
None (Nachricht ignorieren task/submit )None (ignore the task/submit message) Die einfachste Antwort ist überhaupt keine Antwort.The simplest response is no response at all. Ihr bot muss nicht Antworten, wenn der Benutzer mit dem Aufgabenmodul fertig ist.Your bot is not required to respond when the user is finished with the task module.
{
"task": {
"type": "message",
"value": "Message text"
}
}
In Microsoft Teams wird der Wert value in einem Popupmeldungsfeld angezeigt.Teams will display the value of value in a popup message box.
{
"task": {
"type": "continue",
"value": <TaskInfo object>
}
}
Ermöglicht es Ihnen, Sequenzen von adaptiven Karten in einer Assistenten-/mehrstufigen Umgebung zu "verketten".Allows you to "chain" sequences of Adaptive cards together in a wizard/multi-step experience. Beachten Sie, dass das Verketten von adaptiven Karten in eine Sequenz ein erweitertes Szenario ist und hier nicht dokumentiert ist. Die Node.js-Beispiel-App unterstützt Sie jedoch und wie Sie funktioniert, ist in der Readme.MD-Dateidokumentiert.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.

Nutzlast von Task/FETCH und Task/Submit-NachrichtenPayload of task/fetch and task/submit messages

Dieser Abschnitt definiert das Schema dessen, was Ihr bot erhält, wenn er ein task/fetch oder task/submit bot Framework Activity -Objekt empfängt.This section defines the schema of what your bot receives when it receives a task/fetch or task/submit Bot Framework Activity object. Die wichtige obere Ebene wird unten angezeigt:The important top-level appear below:

EigenschaftProperty BeschreibungDescription
type Wird immerinvokeWill always be invoke
name Entweder task/fetch odertask/submitEither task/fetch or task/submit
value Die vom Entwickler definierte Nutzlast.The developer-defined payload. Normalerweise spiegelt die Struktur des value Objekts das, was von Teams gesendet wurde.Normally the structure of the value object mirrors what was sent from Teams. In diesem Fall ist es jedoch anders, da wir Dynamic FETCH ( task/fetch ) sowohl von bot-Framework () als value auch von Adaptive Card-Aktionen () unterstützen möchten Action.Submit data , und wir benötigen eine Möglichkeit, Teams context mit dem bot zu kommunizieren, zusätzlich zu dem, was in enthalten war 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.

Dies erfolgt durch Kombinieren der beiden Elemente in einem übergeordneten Objekt: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]
}

Beispiel: empfangen und reagieren auf Tasks/FETCH-und Task/Submit-Invoke-Nachrichten – Node.jsExample: Receiving and responding to task/fetch and task/submit invoke messages - Node.js

Hinweis

Der folgende Beispielcode wurde zwischen der technischen Vorschau und der endgültigen Version dieses Features geändert: das Schema der task/fetch Anforderung wurde geändert, um zu verfolgen, was im vorherigen Abschnitt dokumentiertwurde.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. Das heißt, die Dokumentation war richtig, aber die Implementierung war nicht.That is, the documentation was correct but the implementation was not. In den // for Technical Preview [...] Kommentaren unten finden Sie Informationen zu den geänderten Funktionen.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)
            }
        }
    }
}

Siehe auch Microsoft Teams-Beispielcode für Aufgaben Module – Beispiele für nodejs und bot-Framework.See also, Microsoft Teams task module sample code — nodejs and Bot Framework samples.

Beispiel: empfangen und reagieren auf Tasks/FETCH-und Task/Submit-Invoke-Nachrichten-C #Example: Receiving and responding to task/fetch and task/submit invoke messages - C#

In C#-Bots invoke werden Nachrichten von einem HttpResponseMessage() Controller verarbeitet, der eine Activity Nachricht verarbeitet.In C# bots, invoke messages are processed by an HttpResponseMessage() controller processing an Activity message. Die task/fetch task/submit Anforderungen und Antworten sind JSON.The task/fetch and task/submit requests and responses are JSON. In C# ist es nicht so bequem, sich mit RAW-JSON wie in Node.js zu beschäftigen, daher benötigen Sie Wrapperklassen, um die Serialisierung von und zu JSON zu verarbeiten.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. Es gibt noch keine direkte Unterstützung dafür im Microsoft Teams C# SDK , aber Sie sehen ein Beispiel dafür, wie diese einfachen Wrapperklassen in der c#-Beispiel- Appaussehen würden.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.

Im folgenden finden Sie Beispielcode in C# zur Behandlung task/fetch und task/submit Nachrichten mit diesen Wrapperklassen ( TaskInfo , TaskEnvelope ), die aus dem Beispielentnommen wurden: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;
}

Im obigen Beispiel nicht dargestellt ist die- SetTaskInfo() Funktion, die die height , width und die title Eigenschaften des TaskInfo Objekts für jeden Fall festlegt.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. Hier ist der Quellcode für SetTaskInfo ().Here's the source code for SetTaskInfo().

Bot-Framework-Karten Aktionen vs. Adaptive Karten Aktion. Submit-AktionenBot Framework card actions vs. Adaptive card Action.Submit actions

Das Schema für Aktionen von bot-Framework-Karten unterscheidet sich geringfügig von adaptiven Karten Action.Submit Aktionen.The schema for Bot Framework card actions is slightly different from Adaptive card Action.Submit actions. Dadurch unterscheidet sich auch die Möglichkeit zum Aufrufen von Aufgaben Modulen geringfügig: das data Objekt in Action.Submit enthält ein msteams Objekt, sodass es nicht mit anderen Eigenschaften in der Karte in Konflikt kommt.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. Die folgende Tabelle zeigt ein Beispiel:The following table shows an example of each:

Bot-Framework-Karten AktionBot Framework card action Adaptive Karten Aktion. Submit-AktionAdaptive card Action.Submit action
{
"type": "invoke",
"title": "Buy",
"value": {
"type": "task/fetch",
<...>
}
}
{
"type": "Action.Submit",
"id": "btnBuy",
"title": "Buy",
"data": {
<...>,
"msteams": {
"type": "task/fetch"
}
}
}