Konvertieren eines .NET-Bots der Version 3 in einen SkillConvert a .NET v3 bot to a skill

gilt für: SDK v4APPLIES TO: SDK v4

In diesem Artikel erfahren Sie, wie Sie drei .NET-Beispielbots der Version 3 in Skills konvertieren und einen Skill-Consumer der Version 4 erstellen, der auf diese Skills zugreifen kann.This article describes how to convert 3 sample .NET v3 bots to skills and to create a v4 skill consumer that can access these skills. Wenn Sie einen JavaScript-Bot der Version 3 in einen Skill konvertieren möchten, lesen Sie Konvertieren eines JavaScript-Bots der Version 3 in einen Skill.To convert a JavaScript v3 bot to a skill, see how to Convert a JavaScript v3 bot to a skill. Wenn Sie einen .NET-Bot der Version 3 zur Version 4 migrieren möchten, lesen Sie Migrieren eines .NET-Bots der Version 3 zu einem .NET Framework-Bot der Version 4.To migrate a .NET bot from v3 to v4, see how to Migrate a .NET v3 bot to a .NET Framework v4 bot.

VoraussetzungenPrerequisites

  • Visual Studio 2019:Visual Studio 2019.
  • .NET Core 3.1.NET Core 3.1.
  • .NET Framework 4.6.1 oder höher.NET Framework 4.6.1 or later.
  • Ein Azure-Abonnement.An Azure subscription. Wenn Sie kein Azure-Abonnement besitzen, können Sie ein kostenloses Konto erstellen, bevor Sie beginnen.If you don't have an Azure subscription, create a free account before you begin.
  • Kopien der zu konvertierenden .NET-Beispielbots der Version 3 (Echo-Bot, PizzaBot und SimpleSandwichBot)Copies of the v3 .NET sample bots to convert: an echo bot, the PizzaBot, and the SimpleSandwichBot.
  • Eine Kopie des exemplarischen .NET-Skill-Consumers der Version 4: SimpleRootBotA copy of the v4 .NET sample skill consumer: SimpleRootBot.

Informationen zu den BotsAbout the bots

In diesem Artikel wird jeder Bot der Version 3 aktualisiert, um als Skill zu fungieren.In this article, each v3 bot is updated to act as a skill. Die zu Skills konvertierten Bots können mit dem enthaltenen Skill-Consumer der Version 4 getestet werden.A v4 skill consumer is included, so that you can test the converted bots as skills.

  • Der Echo-Bot gibt empfangene Nachrichten zurück.The EchoBot echoes back messages it receives. Als Skill wird er beendet, wenn er die Nachricht „end“ oder „stop“ erhält.As a skill, it completes when it receives an "end" or "stop" message. Der zu konvertierende Bot basiert auf der Projektvorlage „Bot Builder Echo Bot“ der Version 3.The bot to convert is based on the v3 Bot Builder Echo Bot project template.
  • Der PizzaBot führt den Benutzer durch eine Pizzabestellung.The PizzaBot walks a user through ordering a pizza. Als Skill gibt er die Bestellung des Benutzers nach Abschluss des Vorgangs an den übergeordneten Bot zurück.As a skill, it sends the user's order back to the parent when finished.
  • Der SimpleSandwichBot führt den Benutzer durch eine Sandwichbestellung.The SimpleSandwichBot walks a user through ordering a sandwich. Als Skill gibt er die Bestellung des Benutzers nach Abschluss des Vorgangs an den übergeordneten Bot zurück.As a skill, it sends the user's order back to the parent when finished.

Darüber hinaus veranschaulicht der SimpleRootBot als Skill-Consumer der Version 4, wie die Skills genutzt werden, und ermöglicht das Testen der Skills.Also, a v4 skill consumer, the SimpleRootBot, demonstrates how to consume the skills and allows you to test them.

Um die Skills mit dem Skill-Consumer testen zu können, müssen alle vier Bots gleichzeitig ausgeführt werden.To use the skill consumer to test the skills, all 4 bots need to be running at the same time. Die Bots können lokal mit Bot Framework Emulator getestet werden. Dabei verwendet jeder Bot einen anderen lokalen Port.The bots can be tested locally using the Bot Framework Emulator, with each bot using a different local port.

Erstellen der Azure-Ressourcen für die BotsCreate Azure resources for the bots

Für die Authentifizierung zwischen Bots muss jeder beteiligte Bot über eine gültige App-ID und ein Kennwort verfügen.Bot-to-bot authentication requires that each participating bot has a valid app ID and password.

  1. Erstellen Sie bei Bedarf eine geeignete Botkanalregistrierung für die Bots.Create a Bot Channels Registration for the bots as needed.
  2. Notieren Sie sich jeweils die App-ID und das Kennwort.Record the app ID and password for each one.

KonvertierungsprozessConversion process

Die Konvertierung eines vorhandenen Bots in einen Skill-Bot umfasst nur wenige Schritte. Diese werden in den nächsten Abschnitten erläutert.To convert an existing bot to a skill bot takes just a few steps, as outlined in the next couple sections. Ausführlichere Informationen finden Sie unter Grundlegendes zu Qualifikationen.For more in-depth information, see about skills.

  • Aktualisieren Sie die Datei web.config des Bots, um die App-ID und das Kennwort des Bots festzulegen und eine Eigenschaft für zulässige Aufrufer hinzuzufügen.Update the bot's web.config file to set the bot's app ID and password and to add an allowed callers property.
  • Fügen Sie eine Anspruchsüberprüfung hinzu.Add claims validation. Dadurch wird der Skill-Zugriff auf Benutzer und Ihren Stamm-Bot beschränkt.This will restrict access to the skill so that only users or your root bot can access the skill. Weitere Informationen zur standardmäßigen und benutzerdefinierten Anspruchsüberprüfung finden Sie im Abschnitt Zusätzliche Informationen.See the additional information section for more information about default and custom claims validation.
  • Ändern Sie den Nachrichtencontroller des Bots, um endOfConversation-Aktivitäten vom Stamm-Bot zu behandeln.Modify the bot's messages controller to handle endOfConversation activities from the root bot.
  • Ändern Sie den Botcode so, dass bei Abschluss des Skills eine endOfConversation-Aktivität zurückgegeben wird.Modify the bot code to return an endOfConversation activity when the skill completes.
  • Bei Abschluss des Skills müssen der Konversationszustand gelöscht und die Ressourcen freigegeben werden (sofern vorhanden).Whenever the skill completes, if it has conversation state or maintains resources, it should clear its conversation state and release resources.
  • Fügen Sie optional eine Manifestdatei hinzu.Optionally add a manifest file. Da ein Skill-Consumer nicht immer über Zugriff auf den Qualifikationscode verfügt, sollten Sie ein Qualifikationsmanifest verwenden, um Folgendes zu beschreiben: Aktivitäten, die die Qualifikation empfangen und generieren kann, die Eingabe- und Ausgabeparameter und die Endpunkte der Qualifikation.Since a skill consumer does not necessarily have access to the skill code, use a skill manifest to describe the activities the skill can receive and generate, its input and output parameters, and the skill's endpoints. Das aktuelle Manifestschema ist skill-manifest-2.0.0.json.The current manifest schema is skill-manifest-2.0.0.json.

Konvertieren des Echo-BotsConvert the echo bot

  1. Erstellen Sie auf der Grundlage der Projektvorlage Bot Builder Echo Bot der Version 3 ein neues Projekt, und konfigurieren Sie es für die Verwendung des Ports 3979.Create a new project from the v3 Bot Builder Echo Bot project template, and set it to use port 3979.

    1. Erstellen Sie das Projekt.Create the project.
    2. Öffnen Sie die Eigenschaften des Projekts.Open the project's properties.
    3. Wählen Sie die Kategorie Web aus, und legen Sie die Projekt-URL auf http://localhost:3979/ fest.Select the Web category, and set the Project Url to http://localhost:3979/.
    4. Speichern Sie Ihre Änderungen, und schließen Sie die Registerkarte mit den Eigenschaften.Save your changes and close the properties tab.
  2. Fügen Sie der Konfigurationsdatei die App-ID und das Kennwort des Echo-Bots hinzu.To the configuration file, add the echo bot's app ID and password. Fügen Sie in den App-Einstellungen außerdem die Eigenschaft EchoBotAllowedCallers hinzu, und fügen Sie dem Wert die App-ID des einfachen Stamm-Bots hinzu.Also in app settings, add an EchoBotAllowedCallers property and add the simple root bot's app ID to its value.

    V3EchoBot\Web.configV3EchoBot\Web.config

    <appSettings>
      <!-- update these with your Microsoft App Id and your Microsoft App Password-->
      <add key="MicrosoftAppId" value="YOUR Echo bot's MicrosoftAppId" />
      <add key="MicrosoftAppPassword" value="YOUR Echo bot's MicrosoftAppPassword" />
      <add key="EchoBotAllowedCallers" value="YOUR root bot's MicrosoftAppId" />
    </appSettings>
    
  3. Fügen Sie eine benutzerdefinierte Anspruchsüberprüfung und eine unterstützende Authentifizierungskonfigurationsklasse hinzu.Add a custom claims validator and a supporting authentication configuration class.

    V3EchoBot\Authentication\CustomAllowedCallersClaimsValidator.csV3EchoBot\Authentication\CustomAllowedCallersClaimsValidator.cs

    Durch den folgenden Code wird eine benutzerdefinierte Anspruchsüberprüfung implementiert und die Ausnahme UnauthorizedAccessException ausgelöst, wenn die Überprüfung nicht erfolgreich ist.This implements custom claims validation and throws an UnauthorizedAccessException if validation fails.

    using Microsoft.Bot.Connector.SkillAuthentication;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    
    namespace Microsoft.Bot.Sample.EchoBot.Authentication
    {
        /// <summary>
        /// Sample claims validator that loads an allowed list from configuration if present
        /// and checks that requests are coming from allowed parent bots.
        /// </summary>
        public class CustomAllowedCallersClaimsValidator : ClaimsValidator
        {
            private readonly IList<string> _allowedCallers;
    
            public CustomAllowedCallersClaimsValidator(IList<string> allowedCallers)
            {
                // AllowedCallers is the setting in web.config file
                // that consists of the list of parent bot IDs that are allowed to access the skill.
                // To add a new parent bot simply go to the AllowedCallers and add
                // the parent bot's Microsoft app ID to the list.
    
                _allowedCallers = allowedCallers ?? throw new ArgumentNullException(nameof(allowedCallers));
                if (!_allowedCallers.Any())
                {
                    throw new ArgumentNullException(nameof(allowedCallers), "AllowedCallers must contain at least one element of '*' or valid MicrosoftAppId(s).");
                }
            }
    
            /// <summary>
            /// This method is called from JwtTokenValidation.ValidateClaimsAsync
            /// </summary>
            /// <param name="claims"></param>
            public override Task ValidateClaimsAsync(IList<Claim> claims)
            {
                if (claims == null)
                {
                    throw new ArgumentNullException(nameof(claims));
                }
    
                if (!claims.Any())
                {
                    throw new UnauthorizedAccessException("ValidateClaimsAsync.claims parameter must contain at least one element.");
                }
    
                if (SkillValidation.IsSkillClaim(claims))
                {
                    // if _allowedCallers has one item of '*', allow all parent bot calls and do not validate the appid from claims
                    if (_allowedCallers.Count == 1 && _allowedCallers[0] == "*")
                    {
                        return Task.CompletedTask;
                    }
    
                    // Check that the appId claim in the skill request is in the list of skills configured for this bot.
                    var appId = JwtTokenValidation.GetAppIdFromClaims(claims).ToUpperInvariant();
                    if (_allowedCallers.Contains(appId))
                    {
                        return Task.CompletedTask;
                    }
    
                    throw new UnauthorizedAccessException($"Received a request from a bot with an app ID of \"{appId}\". To enable requests from this caller, add the app ID to your configuration file.");
                }
    
                throw new UnauthorizedAccessException($"ValidateClaimsAsync called without a Skill claim in claims.");
            }
        }
    }
    

    V3EchoBot\Authentication\CustomSkillAuthenticationConfiguration.csV3EchoBot\Authentication\CustomSkillAuthenticationConfiguration.cs

    Durch den folgenden Code werden die Informationen zu zulässigen Aufrufern aus der Konfigurationsdatei geladen und die Ansprüche mithilfe von CustomAllowedCallersClaimsValidator überprüft.This loads the allowed callers information from the configuration file and uses the CustomAllowedCallersClaimsValidator for claims validation.

    using Microsoft.Bot.Connector.SkillAuthentication;
    using System.Configuration;
    using System.Linq;
    
    namespace Microsoft.Bot.Sample.EchoBot.Authentication
    {
        public class CustomSkillAuthenticationConfiguration : AuthenticationConfiguration
        {
            private const string AllowedCallersConfigKey = "EchoBotAllowedCallers";
            public CustomSkillAuthenticationConfiguration()
            {
                // Could pull this list from a DB or anywhere.
                var allowedCallers = ConfigurationManager.AppSettings[AllowedCallersConfigKey].Split(',').Select(s => s.Trim().ToUpperInvariant()).ToList();
                ClaimsValidator = new CustomAllowedCallersClaimsValidator(allowedCallers);
            }
        }
    }
    
  4. Aktualisieren Sie die MessagesController-Klasse.Update the MessagesController class.

    V3EchoBot\Controllers\MessagesController.csV3EchoBot\Controllers\MessagesController.cs

    Aktualisieren Sie die using-Anweisungen.Update the using statements.

    using System.Diagnostics;
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Http;
    using Autofac;
    using Microsoft.Bot.Builder.Dialogs;
    using Microsoft.Bot.Builder.Dialogs.Internals;
    using Microsoft.Bot.Connector;
    using Microsoft.Bot.Connector.SkillAuthentication;
    using Microsoft.Bot.Sample.EchoBot.Authentication;
    

    Aktualisieren Sie das Klassenattribut von BotAuthentication in SkillBotAuthentication.Update the class attribute from BotAuthentication to SkillBotAuthentication. Verwenden Sie den optionalen Parameter AuthenticationConfigurationProviderType, um den Anbieter für die benutzerdefinierte Anspruchsüberprüfung zu verwenden.Use the optional AuthenticationConfigurationProviderType parameter to use the custom claims validation provider.

    // Specify which type provides the authentication configuration to allow for validation for skills.
    [SkillBotAuthentication(AuthenticationConfigurationProviderType = typeof(CustomSkillAuthenticationConfiguration))]
    public class MessagesController : ApiController
    

    Fügen Sie in der Methode HandleSystemMessage eine Bedingung für die Behandlung einer Nachricht vom Typ endOfConversation hinzu.In the HandleSystemMessage method, add a condition to handle an endOfConversation message. Dadurch kann der Skill den Zustand löschen und Ressourcen freigeben, wenn die Konversation vom Skill-Consumer beendet wird.This allows the skill to clear state and release resources when the conversation is ended from the skill consumer.

    if (messageType == ActivityTypes.EndOfConversation)
    {
        Trace.TraceInformation($"EndOfConversation: {message}");
    
        // This Recipient null check is required for PVA manifest validation.
        // PVA will send an EOC activity with null Recipient.
        if (message.Recipient != null)
        {
            // Clear the dialog stack if the root bot has ended the conversation.
            using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
            {
                var botData = scope.Resolve<IBotData>();
                await botData.LoadAsync(default(CancellationToken));
    
                var stack = scope.Resolve<IDialogStack>();
                stack.Reset();
    
                await botData.FlushAsync(default(CancellationToken));
            }
        }
    }
    
  5. Ändern Sie den Botcode, damit der Skill die Konversation als abgeschlossen kennzeichnen kann, wenn vom Benutzer eine Nachricht vom Typ „end“ oder „stop“ eingeht.Modify the bot code to allow the skill to flag that the conversation is complete when it receives an "end" or "stop" message from the user. Der Skill muss außerdem den Zustand löschen und Ressourcen freigeben, wenn er die Konversation beendet.The skill should also clear state and release resources when it ends the conversation.

    V3EchoBot\Dialogs\RootDialog.csV3EchoBot\Dialogs\RootDialog.cs

    private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as Activity;
    
        // Send an `endOfconversation` activity if the user cancels the skill.
        if (activity.Text.ToLower().Contains("end") || activity.Text.ToLower().Contains("stop"))
        {
            await context.PostAsync($"Ending conversation from the skill...");
            var endOfConversation = activity.CreateReply();
            endOfConversation.Type = ActivityTypes.EndOfConversation;
            endOfConversation.Code = EndOfConversationCodes.UserCancelled;
            await context.PostAsync(endOfConversation);
        }
        else
        {
            await context.PostAsync($"Echo (dotnet V3): {activity.Text}");
            await context.PostAsync($"Say 'end' or 'stop' and I'll end the conversation and back to the parent.");
        }
    
        context.Wait(MessageReceivedAsync);
    }
    
  6. Verwenden Sie dieses Manifest für den Echo-Bot.Use this manifest for the echo bot. Legen Sie die Endpunkt-App-ID auf die App-ID des Bots fest.Set the endpoint app ID to the bot's app ID.

    V3EchoBot\wwwroot\echo-bot-manifest.jsonV3EchoBot\wwwroot\echo-bot-manifest.json

    {
      "$schema": "https://raw.githubusercontent.com/microsoft/botframework-sdk/master/schemas/skills/skill-manifest-2.0.0.json",
      "$id": "YourEchoBotHandle",
      "name": "V3 Echo Skill Bot",
      "version": "1.0",
      "description": "This is a sample skill for echoing what the user sent the bot.",
      "publisherName": "Microsoft",
      "privacyUrl": "https://microsoft.com/privacy",
      "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
      "license": "",
      "iconUrl": "https://myskill.contoso.com/icon.png",
      "tags": [
        "sample",
        "echo"
      ],
      "endpoints": [
        {
          "name": "YourEchoBotName",
          "protocol": "BotFrameworkV3",
          "description": "Default endpoint for the skill",
          "endpointUrl": "http://localhost:3979/api/messages",
          "msAppId": "Your Echo Bot's MicrosoftAppId"
        }
      ],
      "activities": {
        "EchoDotNetV3": {
          "description": "Echo user responses",
          "type": "message",
          "name": "V3Echo"
        }
      }
    }
    

    Informationen zum Schema des Qualifikationsmanifests finden Sie unter skill-manifest-2.0.0.json.For the skill-manifest schema, see skill-manifest-2.0.0.json.

Konvertieren des Pizza-BotsConvert the pizza bot

  1. Öffnen Sie Ihre Kopie des PizzaBot-Projekts, und konfigurieren Sie es für die Verwendung des Ports 3980.Open your copy of the PizzaBot project, and set it to use port 3980.

    1. Öffnen Sie die Eigenschaften des Projekts.Open the project's properties.
    2. Wählen Sie die Kategorie Web aus, und legen Sie die Projekt-URL auf http://localhost:3980/ fest.Select the Web category, and set the Project Url to http://localhost:3980/.
    3. Speichern Sie Ihre Änderungen, und schließen Sie die Registerkarte mit den Eigenschaften.Save your changes and close the properties tab.
  2. Fügen Sie der Konfigurationsdatei die App-ID und das Kennwort des Pizza-Bots hinzu.To the configuration file, add the pizza bot's app ID and password. Fügen Sie in den App-Einstellungen außerdem die Eigenschaft AllowedCallers hinzu, und fügen Sie dem Wert die App-ID des einfachen Stamm-Bots hinzu.Also in app settings, add an AllowedCallers property and add the simple root bot's app ID to its value.

    V3PizzaBot\Web.configV3PizzaBot\Web.config

    <appSettings>
      <!-- update these with your Microsoft App Id and your Microsoft App Password-->
      <add key="MicrosoftAppId" value="YOUR Pizza bot's MicrosoftAppId" />
      <add key="MicrosoftAppPassword" value="YOUR Pizza bot's MicrosoftAppPassword" />
      <add key="AllowedCallers" value="YOUR root bot's MicrosoftAppId" />
    </appSettings>
    
  3. Fügen Sie eine Klasse vom Typ ConversationHelper mit Hilfsmethoden für Folgendes hinzu:Add a ConversationHelper class that has helper methods to

    • Senden der Aktivität endOfConversation bei Abschluss des Skills.Send the endOfConversation activity when the skill ends. Dadurch können die Bestellinformationen in der Eigenschaft Value der Aktivität zurückgegeben werden, und die Eigenschaft Code kann so festgelegt werden, dass sie Aufschluss über den Grund für das Konversationsende gibt.This can return the order information in the activity's Value property and set the Code property to reflect why the conversation ended.
    • Löschen des Konversationszustands und Freigeben ggf. zugeordneter RessourcenClear conversation state and release any associated resources.

    V3PizzaBot\ConversationHelper.csV3PizzaBot\ConversationHelper.cs

    using System;
    using System.Collections.Concurrent;
    using System.Configuration;
    using System.Threading;
    using System.Threading.Tasks;
    using Autofac;
    using Microsoft.Bot.Builder.Dialogs;
    using Microsoft.Bot.Builder.Dialogs.Internals;
    using Microsoft.Bot.Connector;
    using Newtonsoft.Json;
    
    namespace Microsoft.Bot.Sample.PizzaBot
    {
        internal static class ConversationHelper
        {
            private static readonly ConcurrentDictionary<string, ConnectorClient> _connectorClientCache = new ConcurrentDictionary<string, ConnectorClient>();
    
            /// <summary>
            /// Helper method that sends an `endOfConversation` activity.
            /// </summary>
            /// <param name="incomingActivity">The incoming user activity for this turn.</param>
            /// <param name="order">Optional. The completed order.</param>
            /// <param name="endOfConversationCode">Optional. The EndOfConversationCode to send to the parent bot.
            /// Defaults to EndOfConversationCodes.CompletedSuccessfully.</param>
            /// <remarks>Sending the `endOfConversation` activity when the conversation completes allows
            /// the bot to be consumed as a skill.</remarks>
            internal static async Task EndConversation(Activity incomingActivity, PizzaOrder order = null, string endOfConversationCode = EndOfConversationCodes.CompletedSuccessfully)
            {
                var connectorClient = _connectorClientCache.GetOrAdd(incomingActivity.ServiceUrl, key =>
                {
                    var appId = ConfigurationManager.AppSettings[MicrosoftAppCredentials.MicrosoftAppIdKey];
                    var appPassword = ConfigurationManager.AppSettings[MicrosoftAppCredentials.MicrosoftAppPasswordKey];
                    return new ConnectorClient(new Uri(incomingActivity.ServiceUrl), appId, appPassword);
                });
    
                // Send End of conversation as reply.
                await connectorClient.Conversations.SendToConversationAsync(incomingActivity.CreateReply("Ending conversation from the skill..."));
                var endOfConversation = incomingActivity.CreateReply();
                if (order != null)
                {
                    endOfConversation.Value = JsonConvert.SerializeObject(order);
                }
                endOfConversation.Type = ActivityTypes.EndOfConversation;
                endOfConversation.Code = endOfConversationCode;
                await connectorClient.Conversations.SendToConversationAsync(endOfConversation);
            }
    
            /// <summary>
            /// Clear the dialog stack and data bags.
            /// </summary>
            /// <param name="activity">The incoming activity to use for scoping the Conversation.Container.</param>
            internal static async Task ClearState(Activity activity)
            {
                // This is required for PVA manifest validation.
                // PVA will send an EOC activity with null Recipient.
                if (activity.Recipient == null)
                    return;
    
                using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
                {
                    var botData = scope.Resolve<IBotData>();
                    await botData.LoadAsync(default(CancellationToken));
    
                    // Some skills might persist data between invokations.
                    botData.UserData.Clear();
                    botData.ConversationData.Clear();
                    botData.PrivateConversationData.Clear();
    
                    var stack = scope.Resolve<IDialogStack>();
                    stack.Reset();
                    
                    await botData.FlushAsync(default(CancellationToken));
                }
            }
        }
    }
    
  4. Aktualisieren Sie die MessagesController-Klasse.Update the MessagesController class.

    V3PizzaBot\Controllers\MessagesController.csV3PizzaBot\Controllers\MessagesController.cs

    Aktualisieren Sie die using-Anweisungen.Update the using statements.

    using System.Web.Http;
    using System.Threading.Tasks;
    
    using Microsoft.Bot.Connector;
    using Microsoft.Bot.Builder.FormFlow;
    using Microsoft.Bot.Builder.Dialogs;
    using System.Web.Http.Description;
    using System.Net.Http;
    using System.Diagnostics;
    using Microsoft.Bot.Connector.SkillAuthentication;
    using Microsoft.Bot.Builder.Dialogs.Internals;
    using Autofac;
    using System.Threading;
    

    Aktualisieren Sie das Klassenattribut von BotAuthentication in SkillBotAuthentication.Update the class attribute from BotAuthentication to SkillBotAuthentication. Dieser Bot verwendet die standardmäßige Anspruchsüberprüfung.This bot uses the default claims validator.

    [SkillBotAuthentication]
    public class MessagesController : ApiController
    

    Ändern Sie in der Methode Post die Aktivitätsbedingung message, damit der Benutzer den Bestellprozess innerhalb des Skills abbrechen kann.In the Post method, modify the message activity condition to allow the user to cancel their ordering process from within the skill. Fügen Sie außerdem eine Aktivitätsbedingung vom Typ endOfConversation hinzu, damit der Skill den Zustand löschen und Ressourcen freigeben kann, wenn die Konversation vom Skill-Consumer beendet wird.Also, add an endOfConversation activity condition to allow the skill to clear state and release resources when the conversation is ended from the skill consumer.

    case ActivityTypes.Message:
        // Send an `endOfconversation` activity if the user cancels the skill.
        if (activity.Text.ToLower().Contains("end") || activity.Text.ToLower().Contains("stop"))
        {
            await ConversationHelper.ClearState(activity);
            await ConversationHelper.EndConversation(activity, endOfConversationCode: EndOfConversationCodes.UserCancelled);
        }
        else
        {
            await Conversation.SendAsync(activity, MakeRoot);
        }
        break;
    case ActivityTypes.EndOfConversation:
        Trace.TraceInformation($"EndOfConversation: {activity}");
    
        // Clear the dialog stack if the root bot has ended the conversation.
        await ConversationHelper.ClearState(activity);
    
        break;
    
  5. Ändern Sie den Botcode.Modify the bot code.

    V3PizzaBot\PizzaOrderDialog.csV3PizzaBot\PizzaOrderDialog.cs

    Aktualisieren Sie die using-Anweisungen.Update the using statements.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    using Microsoft.Bot.Builder.Dialogs;
    using Microsoft.Bot.Builder.FormFlow;
    using Microsoft.Bot.Builder.Luis;
    using Newtonsoft.Json;
    using Microsoft.Bot.Builder.Luis.Models;
    using Microsoft.Bot.Connector;
    

    Fügen Sie eine Willkommensnachricht hinzu.Add a welcome message. Dadurch weiß der Benutzer, was passiert, wenn der Stamm-Bot den Pizza-Bot als Skill aufruft.This will help the user know what's going on when the root bot invokes the pizza bot as a skill.

    public override async Task StartAsync(IDialogContext context)
    {
        await context.PostAsync("Welcome to the Pizza Order Bot. Let me know if you would like to order a pizza, or know our store hours.");
        await context.PostAsync("Say 'end' or 'stop' and I'll end the conversation and back to the parent.");
    
        await base.StartAsync(context);
    }
    

    Ändern Sie den Botcode, damit der Skill die Konversation als abgeschlossen kennzeichnen kann, wenn der Benutzer die Bestellung abbricht oder abschließt.Modify the bot code to allow the skill to flag that the conversation is complete when the user cancels or completes their order. Der Skill muss außerdem den Zustand löschen und Ressourcen freigeben, wenn er die Konversation beendet.The skill should also clear state and release resources when it ends the conversation.

    private async Task PizzaFormComplete(IDialogContext context, IAwaitable<PizzaOrder> result)
    {
        PizzaOrder order = null;
        try
        {
            order = await result;
        }
        catch (OperationCanceledException)
        {
            await context.PostAsync("You canceled the form!");
    
            // If the user cancels the skill, send an `endOfConversation` activity to the skill consumer.
            await ConversationHelper.EndConversation(context.Activity as Activity, endOfConversationCode: EndOfConversationCodes.UserCancelled);
            return;
        }
    
        if (order != null)
        {
            await context.PostAsync("Your Pizza Order: " + order.ToString());
        }
        else
        {
            await context.PostAsync("Form returned empty response!");
        }
    
        // When the skill completes, send an `endOfConversation` activity and include the finished order.
        await ConversationHelper.EndConversation(context.Activity as Activity, order);
        context.Wait(MessageReceived);
    }
    
  6. Verwenden Sie dieses Manifest für den Pizza-Bot.Use this manifest for the pizza bot. Legen Sie die Endpunkt-App-ID auf die App-ID des Bots fest.Set the endpoint app ID to the bot's app ID.

    V3PizzaBot\wwwroot\pizza-bot-manifest.jsonV3PizzaBot\wwwroot\pizza-bot-manifest.json

    {
      "$schema": "https://raw.githubusercontent.com/microsoft/botframework-sdk/master/schemas/skills/skill-manifest-2.0.0.json",
      "$id": "YourPizzaBotHandle",
      "name": "Pizza Skill Bot",
      "version": "1.0",
      "description": "This is a sample skill for ordering a Pizza.",
      "publisherName": "Microsoft",
      "privacyUrl": "https://microsoft.com/privacy",
      "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
      "license": "",
      "iconUrl": "https://myskill.contoso.com/icon.png",
      "tags": [
        "sample",
        "pizza"
      ],
      "endpoints": [
        {
          "name": "YourPizzaBotName",
          "protocol": "BotFrameworkV3",
          "description": "Default endpoint for the skill",
          "endpointUrl": "http://localhost:3980/api/messages",
          "msAppId": "YOUR Pizza Bot's MicrosoftAppId"
        }
      ],
      "activities": {
        "OrderPizza": {
          "description": "Order a Pizza",
          "type": "message",
          "name": "OrderPizza"
        }
      }
    }
    

    Informationen zum Schema des Qualifikationsmanifests finden Sie unter skill-manifest-2.0.0.json.For the skill-manifest schema, see skill-manifest-2.0.0.json.

Konvertieren des Sandwich-BotsConvert the sandwich bot

  1. Öffnen Sie Ihre Kopie des SimpleSandwichBot-Projekts, und konfigurieren Sie es für die Verwendung des Ports 3981.Open your copy of the SimpleSandwichBot project, and set it to use port 3981.

    1. Öffnen Sie die Eigenschaften des Projekts.Open the project's properties.
    2. Wählen Sie die Kategorie Web aus, und legen Sie die Projekt-URL auf http://localhost:3981/ fest.Select the Web category, and set the Project Url to http://localhost:3981/.
    3. Speichern Sie Ihre Änderungen, und schließen Sie die Registerkarte mit den Eigenschaften.Save your changes and close the properties tab.
  2. Fügen Sie der Konfigurationsdatei die App-ID und das Kennwort des Pizza-Bots hinzu.To the configuration file, add the pizza bot's app ID and password. Fügen Sie in den App-Einstellungen außerdem die Eigenschaft AllowedCallers hinzu, und fügen Sie dem Wert die App-ID des einfachen Stamm-Bots hinzu.Also in app settings, add an AllowedCallers property and add the simple root bot's app ID to its value.

    V3SimpleSandwichBot\Web.configV3SimpleSandwichBot\Web.config

    <appSettings>
      <!-- update these with your Microsoft App Id and your Microsoft App Password-->
      <add key="MicrosoftAppId" value="YOUR Sandwich bot's MicrosoftAppId" />
      <add key="MicrosoftAppPassword" value="YOUR Sandwich bot's MicrosoftAppPassword" />
      <add key="AllowedCallers" value="YOUR root bot's MicrosoftAppId" />
    </appSettings>
    
  3. Fügen Sie eine Klasse vom Typ ConversationHelper mit Hilfsmethoden für Folgendes hinzu:Add a ConversationHelper class that has helper methods to

    • Senden der Aktivität endOfConversation bei Abschluss des Skills.Send the endOfConversation activity when the skill ends. Dadurch können die Bestellinformationen in der Eigenschaft Value der Aktivität zurückgegeben werden, und die Eigenschaft Code kann so festgelegt werden, dass sie Aufschluss über den Grund für das Konversationsende gibt.This can return the order information in the activity's Value property and set the Code property to reflect why the conversation ended.
    • Löschen des Konversationszustands und Freigeben ggf. zugeordneter RessourcenClear conversation state and release any associated resources.

    V3SimpleSandwichBot\ConversationHelper.csV3SimpleSandwichBot\ConversationHelper.cs

    using System;
    using System.Collections.Concurrent;
    using System.Configuration;
    using System.Threading;
    using System.Threading.Tasks;
    using Autofac;
    using Microsoft.Bot.Builder.Dialogs;
    using Microsoft.Bot.Builder.Dialogs.Internals;
    using Microsoft.Bot.Connector;
    using Newtonsoft.Json;
    
    namespace Microsoft.Bot.Sample.SimpleSandwichBot
    {
        internal static class ConversationHelper
        {
            private static readonly ConcurrentDictionary<string, ConnectorClient> _connectorClientCache = new ConcurrentDictionary<string, ConnectorClient>();
    
            /// <summary>
            /// Helper method that sends an `endOfConversation` activity.
            /// </summary>
            /// <param name="incomingActivity">The incoming user activity for this turn.</param>
            /// <param name="order">Optional. The completed order.</param>
            /// <param name="endOfConversationCode">Optional. The EndOfConversationCode to send to the parent bot.
            /// Defaults to EndOfConversationCodes.CompletedSuccessfully.</param>
            /// <remarks>Sending the `endOfConversation` activity when the conversation completes allows
            /// the bot to be consumed as a skill.</remarks>
            internal static async Task EndConversation(Activity incomingActivity, SandwichOrder order = null, string endOfConversationCode = EndOfConversationCodes.CompletedSuccessfully)
            {
                var connectorClient = _connectorClientCache.GetOrAdd(incomingActivity.ServiceUrl, key =>
                {
                    var appId = ConfigurationManager.AppSettings[MicrosoftAppCredentials.MicrosoftAppIdKey];
                    var appPassword = ConfigurationManager.AppSettings[MicrosoftAppCredentials.MicrosoftAppPasswordKey];
                    return new ConnectorClient(new Uri(incomingActivity.ServiceUrl), appId, appPassword);
                });
    
                // Send End of conversation as reply.
                await connectorClient.Conversations.SendToConversationAsync(incomingActivity.CreateReply("Ending conversation from the skill..."));
                var endOfConversation = incomingActivity.CreateReply();
                if (order != null)
                {
                    endOfConversation.Value = JsonConvert.SerializeObject(order);
                }
                endOfConversation.Type = ActivityTypes.EndOfConversation;
                endOfConversation.Code = endOfConversationCode;
                await connectorClient.Conversations.SendToConversationAsync(endOfConversation);
            }
    
            /// <summary>
            /// Clear the dialog stack and data bags.
            /// </summary>
            /// <param name="activity">The incoming activity to use for scoping the Conversation.Container.</param>
            internal static async Task ClearState(Activity activity)
            {
                // This Recipient null check is required for PVA manifest validation.
                // PVA will send an EOC activity with null Recipient.
                if (activity.Recipient == null)
                    return;
    
                using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
                {
                    var botData = scope.Resolve<IBotData>();
                    await botData.LoadAsync(default(CancellationToken));
    
                    // Some skills might persist data between invokations.
                    botData.UserData.Clear();
                    botData.ConversationData.Clear();
                    botData.PrivateConversationData.Clear();
    
                    var stack = scope.Resolve<IDialogStack>();
                    stack.Reset();
    
                    await botData.FlushAsync(default(CancellationToken));
                }
            }
        }
    }
    
  4. Aktualisieren Sie die MessagesController-Klasse.Update the MessagesController class.

    V3SimpleSandwichBot\Controllers\MessagesController.csV3SimpleSandwichBot\Controllers\MessagesController.cs

    Aktualisieren Sie die using-Anweisungen.Update the using statements.

    using System.Threading.Tasks;
    using System.Web.Http;
    
    using Microsoft.Bot.Connector;
    using Microsoft.Bot.Builder.Dialogs;
    using Microsoft.Bot.Builder.FormFlow;
    using System.Net.Http;
    using System.Web.Http.Description;
    using System.Diagnostics;
    using Microsoft.Bot.Connector.SkillAuthentication;
    using Newtonsoft.Json;
    using Microsoft.Bot.Builder.Dialogs.Internals;
    using Autofac;
    using System.Threading;
    

    Aktualisieren Sie das Klassenattribut von BotAuthentication in SkillBotAuthentication.Update the class attribute from BotAuthentication to SkillBotAuthentication. Dieser Bot verwendet die standardmäßige Anspruchsüberprüfung.This bot uses the default claims validator.

    [SkillBotAuthentication]
    public class MessagesController : ApiController
    

    Ändern Sie in der Methode Post die Aktivitätsbedingung message, damit der Benutzer den Bestellprozess innerhalb des Skills abbrechen kann.In the Post method, modify the message activity condition to allow the user to cancel their ordering process from within the skill. Fügen Sie außerdem eine Aktivitätsbedingung vom Typ endOfConversation hinzu, damit der Skill den Zustand löschen und Ressourcen freigeben kann, wenn die Konversation vom Skill-Consumer beendet wird.Also, add an endOfConversation activity condition to allow the skill to clear state and release resources when the conversation is ended from the skill consumer.

    case ActivityTypes.Message:
        if (activity.Text.ToLower().Contains("end") || activity.Text.ToLower().Contains("stop"))
        {
            await ConversationHelper.ClearState(activity);
            await ConversationHelper.EndConversation(activity, endOfConversationCode: EndOfConversationCodes.UserCancelled);
        }
        else
        {
            await Conversation.SendAsync(activity, MakeRootDialog);
        }
    
        break;
    case ActivityTypes.EndOfConversation:
        Trace.TraceInformation($"EndOfConversation: {activity}");
    
        // Clear the dialog stack if the root bot has ended the conversation.
        await ConversationHelper.ClearState(activity);
    
        break;
    
  5. Ändern Sie das Sandwichformular.Modify the sandwich form.

    V3SimpleSandwichBot\Sandwich.csV3SimpleSandwichBot\Sandwich.cs

    Aktualisieren Sie die using-Anweisungen.Update the using statements.

    using Microsoft.Bot.Builder.FormFlow;
    using Microsoft.Bot.Connector;
    using System;
    using System.Collections.Generic;
    using System.Runtime.Remoting.Messaging;
    

    Ändern Sie die Methode BuildForm des Formulars, damit der Skill die Konversation als abgeschlossen kennzeichnen kann.Modify the form's BuildForm method to allow the skill to flag that the conversation is complete.

    public static IForm<SandwichOrder> BuildForm()
    {
        // When the skill completes (OnCompletion), send an `endOfConversation` activity and include the finished order.
        return new FormBuilder<SandwichOrder>()
                .Message("Welcome to the simple sandwich order bot! Say 'end' or 'stop' and I'll end the conversation and back to the parent.")
                .OnCompletion((context, order) => ConversationHelper.EndConversation(context.Activity as Activity, order))
                .Build();
    }
    
  6. Verwenden Sie dieses Manifest für den Sandwich-Bot.Use this manifest for the sandwich bot. Legen Sie die Endpunkt-App-ID auf die App-ID des Bots fest.Set the endpoint app ID to the bot's app ID.

    V3SimpleSandwichBot\wwwroot\sandwich-bot-manifest.jsonV3SimpleSandwichBot\wwwroot\sandwich-bot-manifest.json

    {
      "$schema": "https://raw.githubusercontent.com/microsoft/botframework-sdk/master/schemas/skills/skill-manifest-2.0.0.json",
      "$id": "YourSandwichBotHandle",
      "name": "Sandwich Skill Bot",
      "version": "1.0",
      "description": "This is a sample skill for ordering a sandwich.",
      "publisherName": "Microsoft",
      "privacyUrl": "https://microsoft.com/privacy",
      "copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
      "license": "",
      "iconUrl": "https://myskill.contoso.com/icon.png",
      "tags": [
        "sample",
        "pizza"
      ],
      "endpoints": [
        {
          "name": "YourSandwichBotName",
          "protocol": "BotFrameworkV3",
          "description": "Default endpoint for the skill",
          "endpointUrl": "http://localhost:3981/api/messages",
          "msAppId": "YOUR Sandwich Bots MicrosoftAppId"
        }
      ],
      "activities": {
        "OrderSandwich": {
          "description": "Order a sandwich",
          "type": "message",
          "name": "OrderSandwich"
        }
      }
    }
    

    Informationen zum Schema des Qualifikationsmanifests finden Sie unter skill-manifest-2.0.0.json.For the skill-manifest schema, see skill-manifest-2.0.0.json.

Erstellen des Stamm-Bots der Version 4Create the v4 root bot

Der einfache Stamm-Bot nutzt die drei Skills, sodass Sie überprüfen können, ob die Konvertierungsschritte wie geplant funktioniert haben.The simple root bot consumes the 3 skills and lets you verify that the conversion steps worked as planned. Dieser Bot wird lokal am Port 3978 ausgeführt.This bot will run locally on port 3978.

  1. Fügen Sie der Konfigurationsdatei die App-ID und das Kennwort des Stamm-Bots hinzu.To the configuration file, add the root bot's app ID and password. Fügen Sie für die einzelnen Skills der Version 3 jeweils die entsprechende App-ID hinzu.For each of the v3 skills, add the skill's app ID.

    V4SimpleRootBot\appsettings.jsonV4SimpleRootBot\appsettings.json

    {
      "MicrosoftAppId": "YOUR Root Skill Host bot's MicrosoftAppId",
      "MicrosoftAppPassword": "YOUR Root Skill Host bot's MicrosoftAppPassword",
      "SkillHostEndpoint": "http://localhost:3978/api/skills",
      "BotFrameworkSkills": [
        {
          "Id": "Echo",
          "AppId": "YOUR Echo bot's MicrosoftAppId",
          "SkillEndpoint": "http://localhost:3979/api/messages"
        },
        {
          "Id": "Pizza",
          "AppId": "YOUR Pizza bot's MicrosoftAppId",
          "SkillEndpoint": "http://localhost:3980/api/messages"
        },
        {
          "Id": "Sandwich",
          "AppId": "YOUR Sandwich bot's MicrosoftAppId",
          "SkillEndpoint": "http://localhost:3981/api/messages"
        }
      ]
    }
    

Testen des Stamm-BotsTest the root bot

Laden Sie die aktuelle Version von Bot Framework Emulator herunter, und installieren Sie sie.Download and install the latest Bot Framework Emulator.

  1. Erstellen Sie alle vier Bots, und führen Sie sie lokal auf Ihrem Computer aus.Build and run all four bots locally on your machine.
  2. Verwenden Sie den Emulator, um eine Verbindung mit dem Stamm-Bot herzustellen.Use the Emulator to connect to the root bot.
  3. Testen Sie die Skills und den Skill-Consumer.Test the skills and skill consumer.

Zusätzliche InformationenAdditional information

Authentifizierung zwischen BotsBot-to-bot authentication

Der Stamm und die Qualifikation kommunizieren per HTTP.The root and skill communicate over HTTP. Vom Framework werden Bearertoken und Botanwendungs-IDs verwendet, um die Identität der einzelnen Bots zu bestätigen.The framework uses bearer tokens and bot application IDs to verify the identity of each bot. Es verwendet ein Objekt für die Authentifizierungskonfiguration, um den Authentifizierungsheader eingehender Anforderungen zu überprüfen.It uses an authentication configuration object to validate the authentication header on incoming requests. Sie können der Authentifizierungskonfiguration eine Anspruchsüberprüfung hinzufügen.You can add a claims validator to the authentication configuration. Die Ansprüche werden nach dem Authentifizierungsheader ausgewertet.The claims are evaluated after the authentication header. Ihr Überprüfungscode sollte einen Fehler oder eine Ausnahme auslösen, um die Anforderung abzulehnen.Your validation code should throw an error or exception to reject the request.

Die standardmäßige Anspruchsüberprüfung liest die Anwendungseinstellung AllowedCallers aus der Konfigurationsdatei des Bots.The default claims validator reads the AllowedCallers application setting from the bot's configuration file. Diese Einstellung muss entweder eine kommagetrennte Liste mit den Anwendungs-IDs der Bots enthalten, die den Skill aufrufen dürfen, oder ein Sternchen (*), damit der Skill von allen Bots aufgerufen werden kann.This setting should contain a comma separated list of the application IDs of the bots that are allowed to call the skill, or "*" to allow all bots to call the skill.

Wenn Sie eine benutzerdefinierte Anspruchsüberprüfung verwenden möchten, implementieren Sie von AuthenticationConfiguration und ClaimsValidator abgeleitete Klassen, und verweisen Sie anschließend im Attribut SkillBotAuthentication auf die abgeleitete Authentifizierungskonfiguration.To implement a custom claims validator, implement classes that derive from AuthenticationConfiguration and ClaimsValidator and then reference the derived authentication configuration in the SkillBotAuthentication attribute. Die Schritte 3 und 4 des Abschnitts Konvertieren des Echo-Bots enthalten Beispielklassen für die Anspruchsüberprüfung.Steps 3 and 4 of the convert the echo bot section has example claims validation classes.