/// <summary> /// This method gets called by the runtime. Use this method to add services to the container. /// </summary> /// <param name="services">Specifies the contract for a <see cref="IServiceCollection"/> of service descriptors.</param> /// <seealso cref="IStatePropertyAccessor{T}"/> /// <seealso cref="https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection"/> /// <seealso cref="https://docs.microsoft.com/en-us/azure/bot-service/bot-service-manage-channels?view=azure-bot-service-4.0"/> public void ConfigureServices(IServiceCollection services) { services.AddBot <ComplexDialogBot>(options => { var secretKey = Configuration.GetSection("botFileSecret")?.Value; var botFilePath = Configuration.GetSection("botFilePath")?.Value; var appId = Configuration.GetSection("MicrosoftAppId").Value; var appPassword = Configuration.GetSection("MicrosoftAppPassword").Value; options.CredentialProvider = new SimpleCredentialProvider(appId, appPassword); // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection. var botConfig = BotConfiguration.Load(botFilePath ?? @".\appsettings.json", secretKey); services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded. ({botConfig})")); // Retrieve current endpoint. var environment = _isProduction ? "production" : "development"; var service = botConfig.Services.FirstOrDefault(s => s.Type == "endpoint" && s.Name == environment); if (!(service is EndpointService endpointService)) { throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'."); } options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword); // Creates a logger for the application to use. ILogger logger = _loggerFactory.CreateLogger <ComplexDialogBot>(); // Catches any errors that occur during a conversation turn and logs them. options.OnTurnError = async(context, exception) => { logger.LogError($"Exception caught : {exception}"); await context.SendActivityAsync("Sorry, it looks like something went wrong."); }; }); // Create conversation and user state management objects, using memory storage. IStorage dataStore = new MemoryStorage(); var conversationState = new ConversationState(dataStore); var userState = new UserState(dataStore); // Create and register state accessors. // Accessors created here are passed into the IBot-derived class on every turn. services.AddSingleton <ComplexDialogBotAccessors>(sp => { // Create the custom state accessor. // State accessors enable other components to read and write individual properties of state. var accessors = new ComplexDialogBotAccessors(conversationState, userState) { DialogStateAccessor = conversationState.CreateProperty <DialogState>(ComplexDialogBotAccessors.DialogStateAccessorKey), UserProfileAccessor = userState.CreateProperty <UserProfile>(ComplexDialogBotAccessors.UserAccessorKey), }; return(accessors); }); }
/// <summary> /// Initializes a new instance of the <see cref="ComplexDialogBot"/> class. /// </summary> /// <param name="accessors">A class containing <see cref="IStatePropertyAccessor{T}"/> used to manage state.</param> public ComplexDialogBot(ComplexDialogBotAccessors accessors) { _accessors = accessors ?? throw new ArgumentNullException(nameof(accessors)); // Create a dialog set for the bot. It requires a DialogState accessor, with which // to retrieve the dialog state from the turn context. _dialogs = new DialogSet(accessors.DialogStateAccessor); // Add the prompts we need to the dialog set. _dialogs .Add(new TextPrompt(NamePrompt)) .Add(new NumberPrompt <int>(AgePrompt)) .Add(new ChoicePrompt(SelectionPrompt)); // Add the dialogs we need to the dialog set. _dialogs.Add(new WaterfallDialog(TopLevelDialog) .AddStep(NameStepAsync) .AddStep(AgeStepAsync) .AddStep(StartSelectionStepAsync) .AddStep(AcknowledgementStepAsync)); _dialogs.Add(new WaterfallDialog(ReviewSelectionDialog) .AddStep(SelectionStepAsync) .AddStep(LoopStepAsync)); }