/// <summary> /// Initializes a new instance of the <see cref="PmkbBot"/> class. /// </summary> /// <param name="hostingEnvironment">Hosting environment.</param> /// <param name="accessors">A class containing <see cref="IStatePropertyAccessor{T}"/> used to manage state.</param> /// <param name="services">The <see cref="BotServices"/> required for LUIS.</param> /// <param name="settings">The application's <see cref="Settings"/>.</param> /// <param name="pmkbApi">The <see cref="PmkbApi"/> to request data from.</param> public PmkbBot(IHostingEnvironment hostingEnvironment, BotAccessors accessors, BotServices services, Settings settings, PmkbApi pmkbApi, TelemetryClient telemetryClient) { _hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment)); _accessors = accessors ?? throw new ArgumentNullException(nameof(accessors)); _services = services ?? throw new ArgumentNullException(nameof(services)); _settings = settings ?? throw new ArgumentNullException(nameof(settings)); _pmkbApi = pmkbApi ?? throw new ArgumentNullException(nameof(pmkbApi)); _telemetryClient = telemetryClient ?? throw new ArgumentNullException(nameof(telemetryClient)); if (!_services.LuisServices.ContainsKey(LuisKey)) { throw new ArgumentException($"Invalid configuration. Please check your '.bot' file for a LUIS service named '{LuisKey}'."); } _dialogs = new DialogSet(accessors.ConversationDialogState); _dialogs.Add(new WaterfallDialog(Resources.Prompts.Examples, new WaterfallStep[] { ExamplesChoiceCardStepAsync })); _dialogs.Add(new ChoicePrompt("cardPrompt")); }
/// <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) { var settings = new Settings(Configuration); TelemetryConfiguration.Active.InstrumentationKey = settings.AppInsightsInstrumentationKey; var telemetryClient = new TelemetryClient(); services.AddSingleton(settings); services.AddSingleton(telemetryClient); services.AddScoped(typeof(PmkbApi), (arg) => new PmkbApi(settings.PmkbApiBaseUri, settings.PmkbApiUsername, settings.PmkbApiPassword)); var secretKey = Configuration.GetSection("botFileSecret")?.Value; var botFilePath = Configuration.GetSection("botFilePath")?.Value; if (!File.Exists(botFilePath)) { throw new FileNotFoundException($"The .bot configuration file was not found. botFilePath: {botFilePath}"); } // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection. var botConfig = BotConfiguration.Load(botFilePath ?? @".\pmkb.bot", secretKey); services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded. botFilePath: {botFilePath}")); // Initialize Bot Connected Services clients. var connectedServices = new BotServices(botConfig); services.AddSingleton(sp => connectedServices); services.AddSingleton(sp => botConfig); services.AddBot <PmkbBot>(options => { // 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 <PmkbBot>(); // Catches any errors that occur during a conversation turn and logs them. options.OnTurnError = async(context, exception) => { logger.LogError($"Exception caught : {exception}"); telemetryClient.TrackException(exception); await context.SendActivityAsync("Sorry, it looks like something went wrong."); }; IStorage dataStore = new MemoryStorage(); var conversationState = new ConversationState(dataStore); options.State.Add(conversationState); }); // Create and register state accessors. // Accessors created here are passed into the IBot-derived class on every turn. services.AddSingleton <BotAccessors>(sp => { var options = sp.GetRequiredService <IOptions <BotFrameworkOptions> >().Value; if (options == null) { throw new InvalidOperationException( "BotFrameworkOptions must be configured prior to setting up the State Accessors"); } var conversationState = options.State.OfType <ConversationState>().FirstOrDefault(); if (conversationState == null) { throw new InvalidOperationException( "ConversationState must be defined and added before adding conversation-scoped state accessors."); } var accessors = new BotAccessors(conversationState) { ConversationDialogState = conversationState.CreateProperty <DialogState>(BotAccessors.DialogStateName), }; return(accessors); }); services.AddMvc(); }