protected override async Task OnTeamsSigninVerifyStateAsync(ITurnContext <IInvokeActivity> turnContext, CancellationToken cancellationToken) { Logger.LogInformation("Running dialog with signin/verifystate from an Invoke Activity."); await Dialog.RunAsync(turnContext, ConversationState.CreateProperty <DialogState>(nameof(DialogState)), cancellationToken); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); // Create the Bot Framework Adapter. services.AddSingleton <IBotFrameworkHttpAdapter, AdapterWithErrorHandler>(); // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. services.AddTransient <IBot, PictureBot>(); //init bot services.AddBot <PictureBot>(options => { //read appsettings.json var secretKey = Configuration.GetSection("MicrosoftAppId")?.Value; var botFilePath = Configuration.GetSection("MicrosoftAppPassword")?.Value; options.CredentialProvider = new SimpleCredentialProvider(secretKey, botFilePath); }); services.AddSingleton <PictureBotAccessors>(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"); } //read Cosmos DB settings from appsettings.json CosmosDbStorage _myStorage = new CosmosDbStorage(new CosmosDbStorageOptions { AuthKey = Configuration.GetSection("CosmosDB").GetValue <string>("Key"), CollectionId = Configuration.GetSection("CosmosDB").GetValue <string>("CollectionName"), CosmosDBEndpoint = new Uri(Configuration.GetSection("CosmosDB").GetValue <string>("EndpointURI")), DatabaseId = Configuration.GetSection("CosmosDB").GetValue <string>("DatabaseName"), }); var conversationState = new ConversationState(_myStorage); var userState = new UserState(_myStorage); // Create the custom state accessor. // State accessors enable other components to read and write individual properties of state. var accessors = new PictureBotAccessors(conversationState, userState) { PictureState = conversationState.CreateProperty <PictureState>(PictureBotAccessors.PictureStateName), DialogStateAccessor = conversationState.CreateProperty <DialogState>("DialogState"), }; return(accessors); }); // Create and register a LUIS recognizer. services.AddSingleton(sp => { // Get LUIS information var luisApp = new LuisApplication( "XXXX", "XXXX", "https://westus.api.cognitive.microsoft.com/"); // Specify LUIS options. These may vary for your bot. var luisPredictionOptions = new LuisPredictionOptions { IncludeAllIntents = true, }; // Create the recognizer var recognizer = new LuisRecognizer(luisApp, luisPredictionOptions, true, null); return(recognizer); }); }
/// <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> public void ConfigureServices(IServiceCollection services) { var secretKey = Configuration.GetSection("botFileSecret")?.Value; var botFilePath = Configuration.GetSection("botFilePath")?.Value; // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection. var botConfig = BotConfiguration.Load(botFilePath ?? @".\BotConfiguration.bot", secretKey); services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})")); // Add BotServices singleton. // Create the connected services from .bot file. services.AddSingleton(sp => new BotServices(botConfig)); // Memory Storage is for local bot debugging only. When the bot // is restarted, everything stored in memory will be gone. IStorage dataStore = new MemoryStorage(); // Create and add conversation state. var conversationState = new ConversationState(dataStore); services.AddSingleton(conversationState); // Create and register state accesssors. // Acessors created here are passed into the IBot-derived class on every turn. services.AddSingleton <BotAccessors>(sp => { var options = sp.GetRequiredService <IOptions <BotFrameworkOptions> >().Value; // Create the custom state accessor. // State accessors enable other components to read and write individual properties of state. var accessors = new BotAccessors(conversationState) { DialogStateAccessor = conversationState.CreateProperty <DialogState>(BotAccessors.DialogStateAccessorName), }; return(accessors); }); // Retrieve current endpoint. var environment = _isProduction ? "production" : "development"; var service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault(); if (!(service is EndpointService endpointService)) { throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'."); } // For production bots use the Azure Blob or // Azure CosmosDB storage providers. For the Azure // based storage providers, add the Microsoft.Bot.Builder.Azure // Nuget package to your solution. That package is found at: // https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/ // Un-comment the following lines to use Azure Blob Storage // // Storage configuration name or ID from the .bot file. // const string StorageConfigurationId = "<STORAGE-NAME-OR-ID-FROM-BOT-FILE>"; // var blobConfig = botConfig.FindServiceByNameOrId(StorageConfigurationId); // if (!(blobConfig is BlobStorageService blobStorageConfig)) // { // throw new InvalidOperationException($"The .bot file does not contain an blob storage with name '{StorageConfigurationId}'."); // } // // Default container name. // const string DefaultBotContainer = "botstate"; // var storageContainer = string.IsNullOrWhiteSpace(blobStorageConfig.Container) ? DefaultBotContainer : blobStorageConfig.Container; // IStorage dataStore = new Microsoft.Bot.Builder.Azure.AzureBlobStorage(blobStorageConfig.ConnectionString, storageContainer); var userState = new UserState(dataStore); services.AddSingleton(userState); services.AddBot <BasicBot>(options => { options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword); // Catches any errors that occur during a conversation turn and logs them to currently // configured ILogger. ILogger logger = _loggerFactory.CreateLogger <BasicBot>(); options.OnTurnError = async(context, exception) => { logger.LogError($"Exception caught : {exception}"); await context.SendActivityAsync("Sorry, it looks like something went wrong."); }; }); }
/// <summary> /// This method gets called by the runtime. Use this method to add services to the container. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/> specifies the contract for a collection of service descriptors.</param> /// <seealso cref="IStatePropertyAccessor{T}"/> public void ConfigureServices(IServiceCollection services) { var secretKey = Configuration.GetSection("botFileSecret")?.Value; var botFilePath = Configuration.GetSection("botFilePath")?.Value; // Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection. var botConfig = BotConfiguration.Load(botFilePath ?? @".\dialog-prompt.bot", secretKey); services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot config file could not be loaded. ({botConfig})")); // The Memory Storage used here is for local bot debugging only. When the bot // is restarted, everything stored in memory will be gone. IStorage dataStore = new MemoryStorage(); // Create Conversation State object. // The Conversation State object is where we persist anything at the conversation-scope. var conversationState = new ConversationState(dataStore); // Create and register state accesssors. // Acessors created here are passed into the IBot-derived class on every turn. services.AddSingleton <DialogPromptBotAccessors>(sp => { // Create the custom state accessor. // State accessors enable other components to read and write individual properties of state. var accessors = new DialogPromptBotAccessors(conversationState) { DialogStateAccessor = conversationState.CreateProperty <DialogState>( DialogPromptBotAccessors.DialogStateAccessorKey), ReservationAccessor = conversationState.CreateProperty <DialogPromptBot.Reservation>( DialogPromptBotAccessors.ReservationAccessorKey), }; return(accessors); }); services.AddBot <DialogPromptBot>(options => { // Retrieve current endpoint. var environment = _isProduction ? "production" : "development"; var service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == environment).FirstOrDefault(); 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 <DialogPromptBot>(); // 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."); }; }); }
/// <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="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) { // Memory Storage is for local bot debugging only. When the bot // is restarted, everything stored in memory will be gone. IStorage dataStore = new MemoryStorage(); var conversationState = new ConversationState(dataStore); var userState2 = new UserState(dataStore); // For production bots use the Azure Blob or // Azure CosmosDB storage providers. For the Azure // based storage providers, add the Microsoft.Bot.Builder.Azure // Nuget package to your solution. That package is found at: // https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/ // Un-comment the following lines to use Azure Blob Storage // // Storage configuration name or ID from the .bot file. // const string StorageConfigurationId = "<STORAGE-NAME-OR-ID-FROM-BOT-FILE>"; // var blobConfig = botConfig.FindServiceByNameOrId(StorageConfigurationId); // if (!(blobConfig is BlobStorageService blobStorageConfig)) // { // throw new InvalidOperationException($"The .bot file does not contain an blob storage with name '{StorageConfigurationId}'."); // } // // Default container name. // const string DefaultBotContainer = "<DEFAULT-CONTAINER>"; // var storageContainer = string.IsNullOrWhiteSpace(blobStorageConfig.Container) ? DefaultBotContainer : blobStorageConfig.Container; // IStorage dataStore = new Microsoft.Bot.Builder.Azure.AzureBlobStorage(blobStorageConfig.ConnectionString, storageContainer); // Create and add conversation state. //var conversationState = new ConversationState(dataStore); //services.AddSingleton(conversationState); // The dialogset will need a state store accessor. Since the state accessor is only going to be used by the FoodBotDialogSet, use // AddSingleton to register and inline create the FoodBotDialogSet, at the same time creating the the property accessor in the // conversation state //services.AddSingleton(sp => new EchoBotDialogSet(conversationState.CreateProperty<DialogState>("ECHOBOTDIALOGSTATE"))); services.AddBot <WelcomeUserBot>(options => { var appId = Configuration.GetSection("MicrosoftAppId").Value; var appPassword = Configuration.GetSection("MicrosoftAppPassword").Value; options.CredentialProvider = new SimpleCredentialProvider(appId, appPassword); // Catches any errors that occur during a conversation turn and logs them to currently // configured ILogger. ILogger logger = _loggerFactory.CreateLogger <WelcomeUserBot>(); options.OnTurnError = async(context, exception) => { logger.LogError($"Exception caught : {exception}"); await context.SendActivityAsync("Sorry, it looks like something went wrong."); }; // IStorage dataStore2 = new MemoryStorage(); // var userState = new UserState(dataStore2); options.State.Add(userState2); }); // Create and register state accessors. // Accessors created here are passed into the IBot-derived class on every turn. services.AddSingleton <WelcomeUserStateAccessors>(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 userState = options.State.OfType <UserState>().FirstOrDefault(); if (userState == null) { throw new InvalidOperationException("UserState must be defined and added before adding user-scoped state accessors."); } // Create the custom state accessor. // State accessors enable other components to read and write individual properties of state. var accessors = new WelcomeUserStateAccessors(userState, conversationState) { WelcomeUserState = userState.CreateProperty <WelcomeUserState>(WelcomeUserStateAccessors.WelcomeUserName), }; return(accessors); }); services.AddSingleton <BotState>(conversationState); // The dialogset will need a state store accessor. Since the state accessor is only going to be used by the FoodBotDialogSet, use // AddSingleton to register and inline create the FoodBotDialogSet, at the same time creating the the property accessor in the // conversation state services.AddSingleton(sp => new WelcomeUserBotDialogSet(conversationState.CreateProperty <DialogState>("WELCOMEBOTDIALOGSTATE2"))); services.AddSingleton <IStatePropertyAccessor <DialogState> >(conversationState.CreateProperty <DialogState>("WELCOMEBOTDIALOGSTATE")); services.AddSingleton <WelcomeUserBotDialogSet>(); }
public BookTableDialog(BotServices services, IStatePropertyAccessor <ReservationProperty> reservationsAccessor, IStatePropertyAccessor <OnTurnProperty> onTurnAccessor, IStatePropertyAccessor <UserProfile> userProfileAccessor, ConversationState conversationState) : base(Name) { _services = services ?? throw new ArgumentNullException(nameof(services)); ReservationsAccessor = reservationsAccessor ?? throw new ArgumentNullException(nameof(reservationsAccessor)); OnTurnAccessor = onTurnAccessor ?? throw new ArgumentNullException(nameof(onTurnAccessor)); UserProfileAccessor = userProfileAccessor ?? throw new ArgumentNullException(nameof(userProfileAccessor)); // Create accessors for child dialogs GetLocDialogAccessor = conversationState.CreateProperty <DialogState>(GetLocationDialogState); ConfirmDialogAccessor = conversationState.CreateProperty <DialogState>(ConfirmDialogState); // Add dialogs // Water fall book table dialog var waterfallSteps = new WaterfallStep[] { GetAllRequiredPropertiesAsync, BookTableAsync, }; AddDialog(new WaterfallDialog(BookTableWaterfall, waterfallSteps)); // Get location, date, time & party size prompt. AddDialog(new GetLocationDateTimePartySizePrompt( GetLocationDateTimePartySizePrompt, services, reservationsAccessor, onTurnAccessor, userProfileAccessor, async(promptValidatorContext, cancellationToken) => { // Validation and prompting logic. // Get reservation property. var newReservation = await reservationsAccessor.GetAsync(promptValidatorContext.Context, () => new ReservationProperty()); // If we have a valid reservation, end this prompt. // Otherwise, get LG based on what's available in reservation property if (newReservation.HaveCompleteReservation()) { if (!newReservation.ReservationConfirmed) { if (newReservation.NeedsChange == true) { await promptValidatorContext.Context.SendActivityAsync("What would you like to change ?"); } else { // Greet user with name if we have the user profile set. var userProfile = await userProfileAccessor.GetAsync(promptValidatorContext.Context, () => null); if (userProfile != null && !string.IsNullOrWhiteSpace(userProfile.UserName)) { await promptValidatorContext.Context.SendActivityAsync($"Alright {userProfile.UserName} I have a table for {newReservation.ConfirmationReadOut()}"); } else { await promptValidatorContext.Context.SendActivityAsync($"Ok. I have a table for {newReservation.ConfirmationReadOut()}"); } await promptValidatorContext.Context.SendActivityAsync(MessageFactory.SuggestedActions(new List <string> { "Yes", "No" }, "Should I go ahead and book the table?")); } } else { // Have complete reservation. return(true); } } else { // Readout what has been understood already. var groundedPropertiesReadout = newReservation.GetGroundedPropertiesReadOut(); if (!string.IsNullOrWhiteSpace(groundedPropertiesReadout)) { await promptValidatorContext.Context.SendActivityAsync(groundedPropertiesReadout); } } // Ask user for missing information var prompt = newReservation.GetMissingPropertyReadOut(); if (!string.IsNullOrWhiteSpace(prompt)) { await promptValidatorContext.Context.SendActivityAsync(prompt); } return(false); })); // This dialog is interruptable. So add interruptionDispatcherDialog. AddDialog(new InterruptionDispatcher(onTurnAccessor, conversationState, userProfileAccessor, services)); // When user decides to abandon this dialog, we need to confirm user action. Add confirmation prompt. AddDialog(new ConfirmPrompt(ConfirmCancelPrompt)); }
/** * Constructor. * * @param {BotConfiguration} bot configuration * @param {ConversationState} conversationState * @param {StatePropertyAccessor} accessor for user profile property * @param {StatePropertyAccessor} accessor for on turn property * @param {StatePropertyAccessor} accessor for reservation property */ public WhoAreYouDialog( BotServices botServices, ConversationState conversationState, IStatePropertyAccessor<UserProfile> userProfileAccessor, IStatePropertyAccessor<OnTurnProperty> onTurnAccessor, IStatePropertyAccessor<ReservationProperty> reservationAccessor) : base(Name) { if (botServices == null) { throw new ArgumentNullException(nameof(botServices)); } if (conversationState == null) { throw new ArgumentNullException(nameof(conversationState)); } UserProfileAccessor = userProfileAccessor ?? throw new ArgumentNullException(nameof(userProfileAccessor)); // Keep accessors for the steps to consume OnTurnAccessor = onTurnAccessor ?? throw new ArgumentNullException(nameof(onTurnAccessor)); // Add dialogs var waterfallSteps = new WaterfallStep[] { AskForUserNameAsync, GreetUserAsync, }; AddDialog(new WaterfallDialog( dialogStart, waterfallSteps)); var turnCounterAccessor = conversationState.CreateProperty<CounterState>("turnCounter"); // Add get user name prompt. AddDialog(new GetUserNamePrompt( askUserNamePrompt, botServices, userProfileAccessor, conversationState, onTurnAccessor, turnCounterAccessor, async (promptContext, cancellationToken) => { var userProfile = await userProfileAccessor.GetAsync(promptContext.Context); var counter = await turnCounterAccessor.GetAsync(promptContext.Context); // Prompt validator // Examine if we have a user name and validate it. if (userProfile != null && userProfile.UserName != null) { // We can only accept user names that up to two words. if (userProfile.UserName.Split(" ").Length > 2) { await promptContext.Context.SendActivityAsync("Sorry, I can only accept two words for a name."); await promptContext.Context.SendActivityAsync("You can always say 'My name is <your name>' to introduce yourself to me."); await userProfileAccessor.SetAsync(promptContext.Context, new UserProfile("Human")); // Set updated turn counter await turnCounterAccessor.SetAsync(promptContext.Context, counter); return false; } else { // Capitalize user name userProfile.UserName = char.ToUpper(userProfile.UserName[0]) + userProfile.UserName.Substring(1); // Create user profile and set it to state. await userProfileAccessor.SetAsync(promptContext.Context, userProfile); return true; } } return false; })); // This dialog is interruptable, add interruptionDispatcherDialog AddDialog(new InterruptionDispatcher(onTurnAccessor, conversationState, userProfileAccessor, botServices)); // When user decides to abandon this dialog, we need to confirm user action - add confirmation prompt AddDialog(new ConfirmPrompt(confirmCancelPrompt)); }
/// <summary> /// This method gets called by the runtime. Use this method to add services to the container. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/> specifies the contract for a collection 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 <EchoWithCounterBot>(options => { var blobStore = new AzureBlobTranscriptStore("DefaultEndpointsProtocol=https;AccountName=sq7ofgblobs;AccountKey=2k0LVUrttdcPB50R3DNIgZrB2ff1yapC6Iv0r/SeCKFW4D+bL2ezwy8zO0lCw/Adw2ysPSdsu13OZ07RtXufFw==;EndpointSuffix=core.windows.net", "bot-storage"); var transcriptMiddleware = new TranscriptLoggerMiddleware(blobStore); options.Middleware.Add(transcriptMiddleware); // Creates a logger for the application to use. ILogger logger = _loggerFactory.CreateLogger <EchoWithCounterBot>(); //var secretKey = Configuration.GetSection("botFileSecret")?.Value; //var botFilePath = Configuration.GetSection("botFilePath")?.Value; var secretKey = "s0/1svAFPxOxUcTfsyoILPUcWLfJlACnsGlkzAotEGw="; var botFilePath = "./customerassistant.bot"; 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. BotConfiguration botConfig = null; try { botConfig = BotConfiguration.Load(botFilePath ?? @".\BotConfiguration.bot", secretKey); } catch { var msg = @"Error reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment. - You can find the botFilePath and botFileSecret in the Azure App Service application settings. - If you are running this bot locally, consider adding a appsettings.json file with botFilePath and botFileSecret. - See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration. "; logger.LogError(msg); throw new InvalidOperationException(msg); } services.AddSingleton(sp => botConfig); // Retrieve current endpoint. var environment = _isProduction ? "production" : "development"; var service = botConfig.Services.FirstOrDefault(s => s.Type == "endpoint" && s.Name == environment); if (service == null && _isProduction) { // Attempt to load development environment service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == "development").FirstOrDefault(); logger.LogWarning("Attempting to load development endpoint in production 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); options.ChannelProvider = new ConfigurationChannelProvider(Configuration); // Catches any errors that occur during a conversation turn and logs them. options.OnTurnError = async(context, exception) => { logger.LogError($"Exception caught : {exception}"); Console.WriteLine($"Exception: {exception}"); await context.SendActivityAsync("Sorry, it looks like something went wrong."); }; // The Memory Storage used here is for local bot debugging only. When the bot // is restarted, everything stored in memory will be gone. IStorage dataStore = new MemoryStorage(); // For production bots use the Azure Blob or // Azure CosmosDB storage providers. For the Azure // based storage providers, add the Microsoft.Bot.Builder.Azure // Nuget package to your solution. That package is found at: // https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/ // Uncomment the following lines to use Azure Blob Storage // Storage configuration name or ID from the .bot file. // const string StorageConfigurationId = "<STORAGE-NAME-OR-ID-FROM-BOT-FILE>"; // var blobConfig = botConfig.FindServiceByNameOrId(StorageConfigurationId); // if (!(blobConfig is BlobStorageService blobStorageConfig)) // { // throw new InvalidOperationException($"The .bot file does not contain an blob storage with name '{StorageConfigurationId}'."); // } // // Default container name. // const string DefaultBotContainer = "botstate"; // var storageContainer = string.IsNullOrWhiteSpace(blobStorageConfig.Container) ? DefaultBotContainer : blobStorageConfig.Container; // IStorage dataStore = new Microsoft.Bot.Builder.Azure.AzureBlobStorage(blobStorageConfig.ConnectionString, storageContainer); // Create Conversation State object. // The Conversation State object is where we persist anything at the conversation-scope. var conversationState = new ConversationState(dataStore); var userState = new UserState(dataStore); options.State.Add(conversationState); services.AddSingleton <StateBotAccessors>(sp => { // Create the custom state accessor. return(new StateBotAccessors(conversationState, userState) { ConversationDataAccessor = conversationState.CreateProperty <ConversationData>(StateBotAccessors.ConversationDataName), UserProfileAccessor = userState.CreateProperty <UserData>(StateBotAccessors.UserProfileName), }); }); }); // Create and register state accessors. // Accessors created here are passed into the IBot-derived class on every turn. services.AddSingleton <EchoBotAccessors>(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."); } // Create the custom state accessor. // State accessors enable other components to read and write individual properties of state. var accessors = new EchoBotAccessors(conversationState) { CounterState = conversationState.CreateProperty <CounterState>(EchoBotAccessors.CounterStateName), }; return(accessors); }); }
public StateAccessors(ConversationState conversationState, UserState userState) { ConversationStateAccessors = conversationState.CreateProperty<ConversationData>(nameof(ConversationData)); UserStateAccessors = userState.CreateProperty<UserProfile>(nameof(UserProfile)); }