Пример #1
0
        private static SkillDialog CreateEchoSkillDialog(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillHttpClient skillClient, IConfiguration configuration)
        {
            var botId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;

            //if (string.IsNullOrWhiteSpace(botId))
            //{
            //    throw new ArgumentException($"{MicrosoftAppCredentials.MicrosoftAppIdKey} is not in configuration");
            //}

            var skillHostEndpoint = configuration.GetSection("SkillHostEndpoint")?.Value;

            if (string.IsNullOrWhiteSpace(skillHostEndpoint))
            {
                throw new ArgumentException("SkillHostEndpoint is not in configuration");
            }

            var skillInfo = configuration.GetSection("EchoSkillInfo").Get <BotFrameworkSkill>() ?? throw new ArgumentException("EchoSkillInfo is not set in configuration");

            var skillDialogOptions = new SkillDialogOptions
            {
                BotId = botId,
                ConversationIdFactory = conversationIdFactory,
                SkillClient           = skillClient,
                SkillHostEndpoint     = new Uri(skillHostEndpoint),
                ConversationState     = conversationState,
                Skill = skillInfo
            };
            var echoSkillDialog = new SkillDialog(skillDialogOptions);

            return(echoSkillDialog);
        }
        public async Task BeginDialogOptionsValidation()
        {
            var dialogOptions = new SkillDialogOptions();
            var sut           = new SkillDialog(dialogOptions);
            var client        = new DialogTestClient(Channels.Test, sut);
            await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await client.SendActivityAsync <IMessageActivity>("irrelevant"), "null options should fail");

            client = new DialogTestClient(Channels.Test, sut, new Dictionary <string, string>());
            await Assert.ThrowsExceptionAsync <ArgumentException>(async() => await client.SendActivityAsync <IMessageActivity>("irrelevant"), "options should be of type DialogArgs");

            client = new DialogTestClient(Channels.Test, sut, new BeginSkillDialogOptions());
            await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await client.SendActivityAsync <IMessageActivity>("irrelevant"), "Activity in DialogArgs should be set");
        }
Пример #3
0
        // Dependency injection uses this constructor to instantiate MainDialog
        public MainDialog(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillHttpClient skillClient, SkillsConfiguration skillsConfig, IConfiguration configuration)
            : base(nameof(MainDialog))
        {
            var botId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;

            if (string.IsNullOrWhiteSpace(botId))
            {
                throw new ArgumentException($"{MicrosoftAppCredentials.MicrosoftAppIdKey} is not in configuration");
            }

            _skillsConfig = skillsConfig ?? throw new ArgumentNullException(nameof(skillsConfig));

            if (skillClient == null)
            {
                throw new ArgumentNullException(nameof(skillClient));
            }

            if (conversationState == null)
            {
                throw new ArgumentNullException(nameof(conversationState));
            }

            // ChoicePrompt to render available skills and skill actions
            AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));

            // SkillDialog used to wrap interaction with the selected skill
            var skillDialogOptions = new SkillDialogOptions
            {
                BotId = botId,
                ConversationIdFactory = conversationIdFactory,
                SkillClient           = skillClient,
                SkillHostEndpoint     = skillsConfig.SkillHostEndpoint
            };

            AddDialog(new SkillDialog(skillDialogOptions, conversationState));

            // Main waterfall dialog for this bot
            var waterfallSteps = new WaterfallStep[]
            {
                SelectSkillStepAsync,
                SelectSkillActionStepAsync,
                CallSkillActionStepAsync,
                FinalStepAsync
            };

            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }
Пример #4
0
        private async Task RouteToSkillAsync(DialogContext dc, SkillDialogOptions options)
        {
            // If we can't handle this within the local Bot it's a skill (prefix of s will make this clearer)
            if (options.MatchedSkill != null)
            {
                // We have matched to a Skill
                await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"-->Forwarding your utterance to the {options.MatchedSkill.Name} skill."));

                // Begin the SkillDialog and pass the arguments in
                await dc.BeginDialogAsync(nameof(CustomSkillDialog), options);

                // Pass the activity we have
                await dc.ContinueDialogAsync();
            }
        }
Пример #5
0
        /// <summary>
        /// Helper to create a <see cref="SkillDialogOptions"/> for the skillDialog.
        /// </summary>
        private static SkillDialogOptions CreateSkillDialogOptions(ConversationState conversationState, Mock <BotFrameworkClient> mockSkillClient)
        {
            var dialogOptions = new SkillDialogOptions
            {
                BotId                 = Guid.NewGuid().ToString(),
                SkillHostEndpoint     = new Uri("http://test.contoso.com/skill/messages"),
                ConversationIdFactory = new SimpleConversationIdFactory(),
                ConversationState     = conversationState,
                SkillClient           = mockSkillClient.Object,
                Skill                 = new BotFrameworkSkill
                {
                    AppId         = Guid.NewGuid().ToString(),
                    SkillEndpoint = new Uri("http://testskill.contoso.com/api/messages")
                }
            };

            return(dialogOptions);
        }
Пример #6
0
        // Helper method that creates and adds SkillDialog instances for the configured skills.
        private void AddSkillDialogs(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillHttpClient skillClient, SkillsConfiguration skillsConfig, string botId)
        {
            foreach (var skillInfo in _skillsConfig.Skills.Values)
            {
                // Create the dialog options.
                var skillDialogOptions = new SkillDialogOptions
                {
                    BotId = botId,
                    ConversationIdFactory = conversationIdFactory,
                    SkillClient           = skillClient,
                    SkillHostEndpoint     = skillsConfig.SkillHostEndpoint,
                    ConversationState     = conversationState,
                    Skill = skillInfo
                };

                // Add a SkillDialog for the selected skill.
                AddDialog(new SkillDialog(skillDialogOptions, skillInfo.Id));
            }
        }
Пример #7
0
        private async Task RouteToSkillAsync(DialogContext dc, SkillDialogOptions options)
        {
            // If we can't handle this within the local Bot it's a skill (prefix of s will make this clearer)
            if (options.SkillDefinition != null)
            {
                // We have matched to a Skill
                await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"-->Forwarding your utterance to the {options.SkillDefinition.Name} skill."));

                // Begin the SkillDialog and pass the arguments in
                await dc.BeginDialogAsync(options.SkillDefinition.Id, options);

                // Pass the activity we have
                var result = await dc.ContinueDialogAsync();

                if (result.Status == DialogTurnStatus.Complete)
                {
                    await CompleteAsync(dc);
                }
            }
        }
Пример #8
0
        public void InitSkills()
        {
            // Add Fake Skill registration
            const string fakeSkillName       = "FakeSkill";
            var          fakeSkillDefinition = new SkillDefinition();
            var          fakeSkillType       = typeof(FakeSkill.FakeSkill);

            fakeSkillDefinition.Assembly = fakeSkillType.AssemblyQualifiedName;
            fakeSkillDefinition.Id       = fakeSkillName;
            fakeSkillDefinition.Name     = fakeSkillName;

            SkillConfigurations.Add(fakeSkillDefinition.Id, Services);

            // Options are passed to the SkillDialog
            SkillDialogOptions = new SkillDialogOptions();
            SkillDialogOptions.SkillDefinition = fakeSkillDefinition;

            // Add the SkillDialog to the available dialogs passing the initialized FakeSkill
            Dialogs.Add(new SkillDialog(fakeSkillDefinition, Services, null, TelemetryClient));
        }
        public void InitSkills()
        {
            // Add Fake Skill registration
            const string fakeSkillName       = "FakeSkill";
            var          fakeSkillDefinition = new SkillDefinition();
            var          fakeSkillType       = typeof(FakeSkill.FakeSkill);

            fakeSkillDefinition.Id   = fakeSkillName;
            fakeSkillDefinition.Name = fakeSkillName;

            // Set Assembly name to invalid value
            fakeSkillDefinition.Assembly = "FakeSkill.FakeSkil, Microsoft.Bot.Solutions.Tests, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null";

            SkillConfigurations.Add(fakeSkillDefinition.Id, Services);

            // Options are passed to the SkillDialog
            SkillDialogOptions = new SkillDialogOptions();
            SkillDialogOptions.SkillDefinition = fakeSkillDefinition;

            // Add the SkillDialog to the available dialogs passing the initialized FakeSkill
            Dialogs.Add(new SkillDialog(fakeSkillDefinition, Services, null, null, TelemetryClient, null));
        }
Пример #10
0
        /// <summary>
        /// Create a TestFlow which spins up a CustomSkillDialog ready for the tests to execute against
        /// </summary>
        /// <param name="locale"></param>
        /// <param name="overrideSkillDialogOptions"></param>
        /// <returns></returns>
        public TestFlow GetTestFlow(string locale = null, SkillDialogOptions overrideSkillDialogOptions = null)
        {
            var adapter = new TestAdapter(sendTraceActivity: true)
                          .Use(new AutoSaveStateMiddleware(ConversationState));

            var testFlow = new TestFlow(adapter, async(context, cancellationToken) =>
            {
                var dc = await Dialogs.CreateContextAsync(context);

                if (dc.ActiveDialog != null)
                {
                    var result = await dc.ContinueDialogAsync();
                }
                else
                {
                    var options = overrideSkillDialogOptions ?? SkillDialogOptions;
                    await dc.BeginDialogAsync(options.SkillDefinition.Id, options);
                    var result = await dc.ContinueDialogAsync();
                }
            });

            return(testFlow);
        }
Пример #11
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Configure MVC
            services.AddControllers().AddNewtonsoftJson();

            services.AddSingleton(Configuration);

            // Load settings
            var settings = new BotSettings();

            Configuration.Bind(settings);
            services.AddSingleton(settings);

            // Configure channel provider
            services.AddSingleton <IChannelProvider, ConfigurationChannelProvider>();

            // Configure configuration provider
            services.AddSingleton <ICredentialProvider, ConfigurationCredentialProvider>();

            // Register the skills configuration class.
            var skillsConfig = new SkillsConfiguration(Configuration);

            services.AddSingleton(skillsConfig);

            // Register AuthConfiguration to enable custom claim validation.
            services.AddSingleton(sp => new AuthenticationConfiguration {
                ClaimsValidator = new AllowedCallersClaimsValidator(skillsConfig)
            });

            // Configure telemetry
            services.AddApplicationInsightsTelemetry();
            services.AddSingleton <IBotTelemetryClient, BotTelemetryClient>();
            services.AddSingleton <ITelemetryInitializer, OperationCorrelationTelemetryInitializer>();
            services.AddSingleton <ITelemetryInitializer, TelemetryBotIdInitializer>();
            services.AddSingleton <TelemetryInitializerMiddleware>();
            services.AddSingleton <TelemetryLoggerMiddleware>();

            // Configure bot services
            services.AddSingleton <BotServices>();

            // Configure storage
            // Uncomment the following line for local development without Cosmos Db
            // services.AddSingleton<IStorage, MemoryStorage>();
            services.AddSingleton <IStorage>(new CosmosDbPartitionedStorage(settings.CosmosDb));
            services.AddSingleton <UserState>();
            services.AddSingleton <ConversationState>();

            // Configure localized responses
            var localizedTemplates = new Dictionary <string, string>();
            var templateFile       = "AllResponses";
            var supportedLocales   = new List <string>()
            {
                "en-us", "de-de", "es-es", "fr-fr", "it-it", "zh-cn"
            };

            foreach (var locale in supportedLocales)
            {
                // LG template for en-us does not include locale in file extension.
                var localeTemplateFile = locale.Equals("en-us")
                    ? Path.Combine(".", "Responses", $"{templateFile}.lg")
                    : Path.Combine(".", "Responses", $"{templateFile}.{locale}.lg");

                localizedTemplates.Add(locale, localeTemplateFile);
            }

            services.AddSingleton(new LocaleTemplateManager(localizedTemplates, settings.DefaultLocale ?? "en-us"));

            // Register the Bot Framework Adapter with error handling enabled.
            // Note: some classes use the base BotAdapter so we add an extra registration that pulls the same instance.
            services.AddSingleton <BotFrameworkHttpAdapter, DefaultAdapter>();
            services.AddSingleton <BotAdapter>(sp => sp.GetService <BotFrameworkHttpAdapter>());

            // Register the skills conversation ID factory, the client and the request handler.
            services.AddSingleton <SkillConversationIdFactoryBase, SkillConversationIdFactory>();
            services.AddHttpClient <SkillHttpClient>();
            services.AddSingleton <ChannelServiceHandler, TokenExchangeSkillHandler>();

            // Register dialogs
            services.AddTransient <MainDialog>();
            services.AddTransient <SwitchSkillDialog>();
            services.AddTransient <OnboardingDialog>();

            // Register the SkillDialogs (remote skills).
            var botId = Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value;

            if (string.IsNullOrWhiteSpace(botId))
            {
                throw new ArgumentException($"{MicrosoftAppCredentials.MicrosoftAppIdKey} is not in configuration");
            }

            foreach (var skill in skillsConfig.Skills.Values)
            {
                services.AddSingleton(sp =>
                {
                    var skillDialogOptions = new SkillDialogOptions
                    {
                        BotId = botId,
                        ConversationIdFactory = sp.GetService <SkillConversationIdFactoryBase>(),
                        SkillClient           = sp.GetService <SkillHttpClient>(),
                        SkillHostEndpoint     = skillsConfig.SkillHostEndpoint,
                        Skill             = skill,
                        ConversationState = sp.GetService <ConversationState>()
                    };

                    return(new SkillDialog(skillDialogOptions, skill.Id));
                });
            }

            // Configure TokenExchangeConfig for SSO
            if (settings.TokenExchangeConfig != null)
            {
                services.AddSingleton <ITokenExchangeConfig>(settings.TokenExchangeConfig);
            }

            // Configure bot
            services.AddTransient <IBot, DefaultActivityHandler <MainDialog> >();
        }