From 9d83955edf17ea77c3a631b23fab1b56300f67df Mon Sep 17 00:00:00 2001 From: Kamran Iqbal <29185255+Kaiqb@users.noreply.github.com> Date: Tue, 12 Mar 2019 10:31:31 -0700 Subject: [PATCH 1/2] Updated Welcome User Bot --- .../AdapterWithErrorHandler.cs | 42 +++++ .../ConfigurationCredentialProvider.cs | 16 ++ .../Controllers/BotController.cs | 35 ++++ .../03.welcome-user/Program.cs | 24 +-- .../03.welcome-user/Startup.cs | 156 ++++------------ .../03.welcome-user/WelcomeUser.csproj | 24 +-- .../03.welcome-user/WelcomeUserBot.cs | 170 +++++++----------- .../03.welcome-user/WelcomeUserState.cs | 14 +- .../WelcomeUserStateAccessors.cs | 43 ++--- .../03.welcome-user/appsettings.json | 4 +- 10 files changed, 219 insertions(+), 309 deletions(-) create mode 100644 samples/csharp_dotnetcore/03.welcome-user/AdapterWithErrorHandler.cs create mode 100644 samples/csharp_dotnetcore/03.welcome-user/ConfigurationCredentialProvider.cs create mode 100644 samples/csharp_dotnetcore/03.welcome-user/Controllers/BotController.cs diff --git a/samples/csharp_dotnetcore/03.welcome-user/AdapterWithErrorHandler.cs b/samples/csharp_dotnetcore/03.welcome-user/AdapterWithErrorHandler.cs new file mode 100644 index 0000000000..b0b43802f0 --- /dev/null +++ b/samples/csharp_dotnetcore/03.welcome-user/AdapterWithErrorHandler.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Integration.AspNet.Core; +using Microsoft.Bot.Connector.Authentication; +using Microsoft.Extensions.Logging; + +namespace Microsoft.BotBuilderSamples +{ + public class AdapterWithErrorHandler : BotFrameworkHttpAdapter + { + public AdapterWithErrorHandler(ICredentialProvider credentialProvider, ILogger logger, ConversationState conversationState = null) + : base(credentialProvider) + { + OnTurnError = async (turnContext, exception) => + { + // Log any leaked exception from the application. + logger.LogError($"Exception caught : {exception.Message}"); + + // Send a catch-all appology to the user. + await turnContext.SendActivityAsync("Sorry, it looks like something went wrong."); + + if (conversationState != null) + { + try + { + // Delete the conversationState for the current conversation to prevent the + // bot from getting stuck in a error-loop caused by being in a bad state. + // ConversationState should be thought of as similar to "cookie-state" in a Web pages. + await conversationState.DeleteAsync(turnContext); + } + catch (Exception e) + { + logger.LogError($"Exception caught on attempting to Delete ConversationState : {e.Message}"); + } + } + }; + } + } +} diff --git a/samples/csharp_dotnetcore/03.welcome-user/ConfigurationCredentialProvider.cs b/samples/csharp_dotnetcore/03.welcome-user/ConfigurationCredentialProvider.cs new file mode 100644 index 0000000000..e00b5ef201 --- /dev/null +++ b/samples/csharp_dotnetcore/03.welcome-user/ConfigurationCredentialProvider.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Microsoft.Bot.Connector.Authentication; +using Microsoft.Extensions.Configuration; + +namespace Microsoft.BotBuilderSamples +{ + public class ConfigurationCredentialProvider : SimpleCredentialProvider + { + public ConfigurationCredentialProvider(IConfiguration configuration) + : base(configuration["MicrosoftAppId"], configuration["MicrosoftAppPassword"]) + { + } + } +} diff --git a/samples/csharp_dotnetcore/03.welcome-user/Controllers/BotController.cs b/samples/csharp_dotnetcore/03.welcome-user/Controllers/BotController.cs new file mode 100644 index 0000000000..fa4ea81324 --- /dev/null +++ b/samples/csharp_dotnetcore/03.welcome-user/Controllers/BotController.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Integration.AspNet.Core; + +namespace Microsoft.BotBuilderSamples +{ + // This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot + // implementation at runtime. Multiple different IBot implementations running at different endpoints can be + // achieved by specifying a more specific type for the bot constructor argument. + [Route("api/messages")] + [ApiController] + public class BotController : ControllerBase + { + private readonly IBotFrameworkHttpAdapter _adapter; + private readonly IBot _bot; + + public BotController(IBotFrameworkHttpAdapter adapter, IBot bot) + { + _adapter = adapter; + _bot = bot; + } + + [HttpPost] + public async Task PostAsync() + { + // Delegate the processing of the HTTP POST to the adapter. + // The adapter will invoke the bot. + await _adapter.ProcessAsync(Request, Response, _bot); + } + } +} diff --git a/samples/csharp_dotnetcore/03.welcome-user/Program.cs b/samples/csharp_dotnetcore/03.welcome-user/Program.cs index fdb1892b68..43e91da93e 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/Program.cs +++ b/samples/csharp_dotnetcore/03.welcome-user/Program.cs @@ -11,28 +11,16 @@ public class Program { public static void Main(string[] args) { - BuildWebHost(args).Run(); + CreateWebHostBuilder(args).Build().Run(); } - public static IWebHost BuildWebHost(string[] args) => + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) - .ConfigureLogging((hostingContext, logging) => + .ConfigureLogging((logging) => { - // Add Azure Logging - logging.AddAzureWebAppDiagnostics(); - - // Logging Options. - // There are other logging options available: - // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1 - // logging.AddDebug(); - // logging.AddConsole(); + logging.AddDebug(); + logging.AddConsole(); }) - - // Logging Options. - // Consider using Application Insights for your logging and metrics needs. - // https://azure.microsoft.com/en-us/services/application-insights/ - // .UseApplicationInsights() - .UseStartup() - .Build(); + .UseStartup(); } } diff --git a/samples/csharp_dotnetcore/03.welcome-user/Startup.cs b/samples/csharp_dotnetcore/03.welcome-user/Startup.cs index 98131fb2c5..0efe7fb755 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/Startup.cs +++ b/samples/csharp_dotnetcore/03.welcome-user/Startup.cs @@ -1,154 +1,58 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.IO; -using System.Linq; +using System.Collections.Concurrent; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; using Microsoft.Bot.Builder; -using Microsoft.Bot.Builder.Integration; using Microsoft.Bot.Builder.Integration.AspNet.Core; -using Microsoft.Bot.Configuration; using Microsoft.Bot.Connector.Authentication; -using Microsoft.Extensions.Configuration; +using Microsoft.Bot.Schema; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace Microsoft.BotBuilderSamples { - /// - /// The Startup class configures services and the app's request pipeline. - /// public class Startup { - private ILoggerFactory _loggerFactory; - private bool _isProduction = false; - - public Startup(IHostingEnvironment env) - { - _isProduction = env.IsProduction(); - - var builder = new ConfigurationBuilder() - .SetBasePath(env.ContentRootPath) - .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .AddEnvironmentVariables(); - - Configuration = builder.Build(); - } - - /// - /// Gets the configuration that represents a set of key/value application configuration properties. - /// - /// - /// The that represents a set of key/value application configuration properties. - /// - public IConfiguration Configuration { get; } - - /// - /// This method gets called by the runtime. Use this method to add services to the container. - /// - /// Specifies the contract for a of service descriptors. - /// - /// + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddBot(options => - { - 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 ?? @".\welcome-user.bot", secretKey); - services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded. botFilePath: {botFilePath}")); - - // 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}'."); - } + services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); - options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword); + // Create the credential provider to be used with the Bot Framework Adapter. + services.AddSingleton(); - // Creates a logger for the application to use. - ILogger logger = _loggerFactory.CreateLogger(); + // Create the Bot Framework Adapter with error handling enabled. + services.AddSingleton(); - // 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 the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.) + services.AddSingleton(); - // The Memory Storage used here is for local bot debugging only. When the bot - // is restarted, anything stored in memory will be gone. - IStorage dataStore = new MemoryStorage(); + // Create the User state. + services.AddSingleton(); - // 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 = ""; - // 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 = ""; - // 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 userState = new UserState(dataStore); - options.State.Add(userState); - }); - - // Create and register state accessors. - // Accessors created here are passed into the IBot-derived class on every turn. - services.AddSingleton(sp => - { - var options = sp.GetRequiredService>().Value; - if (options == null) - { - throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the State Accessors"); - } - - var userState = options.State.OfType().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) - { - WelcomeUserState = userState.CreateProperty(WelcomeUserStateAccessors.WelcomeUserName), - }; - - return accessors; - }); + // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. + services.AddTransient(); } - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env) { - _loggerFactory = loggerFactory; + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseHsts(); + } + + app.UseDefaultFiles(); + app.UseStaticFiles(); - app.UseDefaultFiles() - .UseStaticFiles() - .UseBotFramework(); + //app.UseHttpsRedirection(); + app.UseMvc(); } } } diff --git a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUser.csproj b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUser.csproj index 2d2a93349d..7098a29274 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUser.csproj +++ b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUser.csproj @@ -1,27 +1,13 @@ - netcoreapp2.0 + netcoreapp2.1 - - - - - - - - - - - - - - - - Always - + + + + - diff --git a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs index 5a0d790f9f..ff9822b9c7 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs +++ b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs @@ -10,17 +10,15 @@ namespace Microsoft.BotBuilderSamples { - /// - /// Represents a bot that processes incoming activities. - /// For each user interaction, an instance of this class is created and the OnTurnAsync method is called. - /// This is a Transient lifetime service. Transient lifetime services are created - /// each time they're requested. For each Activity received, a new instance of this - /// class is created. Objects that are expensive to construct, or have a lifetime - /// beyond the single turn, should be carefully managed. - /// For example, the object and associated - /// object are created with a singleton lifetime. - /// - public class WelcomeUserBot : IBot + // Represents a bot that processes incoming activities. + // For each user interaction, an instance of this class is created and the OnTurnAsync method is called. + // This is a Transient lifetime service. Transient lifetime services are created + // each time they're requested. For each Activity received, a new instance of this + // class is created. Objects that are expensive to construct, or have a lifetime + // beyond the single turn, should be carefully managed. + // For example, the "MemoryStorage" object and associated + // IStatePropertyAccessor{T} object are created with a singleton lifetime. + public class WelcomeUserBot : ActivityHandler { // Messages sent to the user. private const string WelcomeMessage = @"This is a simple Welcome Bot sample.This bot will introduce you @@ -42,119 +40,77 @@ of the 'ConversationUpdate' event depends on the channel. You can handles 'hello', 'hi', 'help' and 'intro. Try it now, type 'hi'"; // The bot state accessor object. Use this to access specific state properties. - private readonly WelcomeUserStateAccessors _welcomeUserStateAccessors; + private WelcomeUserStateAccessors _welcomeUserStateAccessors; + private UserState _userState; + + // Initializes a new instance of the "WelcomeUserBot" class. + public WelcomeUserBot(UserState userState) + { + _userState = userState; + _welcomeUserStateAccessors = new WelcomeUserStateAccessors(userState); + _welcomeUserStateAccessors.WelcomeUserState = _userState.CreateProperty(WelcomeUserStateAccessors.WelcomeUserName); + } + - /// - /// Initializes a new instance of the class. - /// - /// Bot state accessor object. - public WelcomeUserBot(WelcomeUserStateAccessors statePropertyAccessor) + //Greet when users are added to the conversation. + //Note that all channels do not send the conversation update activity. + //If you find that this bot works in the emulator, but does not in + //another channel the reason is most likely that the channel does not + //send this activity. + protected override async Task OnMembersAddedAsync(IList membersAdded, ITurnContext turnContext, CancellationToken cancellationToken) { - _welcomeUserStateAccessors = statePropertyAccessor ?? throw new System.ArgumentNullException("state accessor can't be null"); + foreach (var member in membersAdded) + { + if (member.Id != turnContext.Activity.Recipient.Id) + { + await turnContext.SendActivityAsync($"Hi there - {member.Name}. {WelcomeMessage}", cancellationToken: cancellationToken); + await turnContext.SendActivityAsync(InfoMessage, cancellationToken: cancellationToken); + await turnContext.SendActivityAsync(PatternMessage, cancellationToken: cancellationToken); + } + } } - /// - /// Every conversation turn for our WelcomeUser Bot will call this method, including - /// any type of activities such as ConversationUpdate or ContactRelationUpdate which - /// are sent when a user joins a conversation. - /// This bot doesn't use any dialogs; it's "single turn" processing, meaning a single - /// request and response. - /// This bot uses UserState to keep track of first message a user sends. - /// - /// A containing all the data needed - /// for processing this conversation turn. - /// (Optional) A that can be used by other objects - /// or threads to receive notice of cancellation. - /// A that represents the work queued to execute. - public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = new CancellationToken()) + protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) { - // use state accessor to extract the didBotWelcomeUser flag var didBotWelcomeUser = await _welcomeUserStateAccessors.WelcomeUserState.GetAsync(turnContext, () => new WelcomeUserState()); - // Handle Message activity type, which is the main activity type for shown within a conversational interface - // Message activities may contain text, speech, interactive cards, and binary or unknown attachments. - // see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types - if (turnContext.Activity.Type == ActivityTypes.Message) + WelcomeUserState welcomeUserState = await _welcomeUserStateAccessors.WelcomeUserState.GetAsync(turnContext, () => new WelcomeUserState()); + + if (didBotWelcomeUser.DidBotWelcomeUser == false) { - // Your bot should proactively send a welcome message to a personal chat the first time - // (and only the first time) a user initiates a personal chat with your bot. - if (didBotWelcomeUser.DidBotWelcomeUser == false) - { - didBotWelcomeUser.DidBotWelcomeUser = true; - // Update user state flag to reflect bot handled first user interaction. - await _welcomeUserStateAccessors.WelcomeUserState.SetAsync(turnContext, didBotWelcomeUser); - await _welcomeUserStateAccessors.UserState.SaveChangesAsync(turnContext); + didBotWelcomeUser.DidBotWelcomeUser = true; + // Update user state flag to reflect bot handled first user interaction. + await _welcomeUserStateAccessors.WelcomeUserState.SetAsync(turnContext, didBotWelcomeUser); + await _welcomeUserStateAccessors.UserState.SaveChangesAsync(turnContext); - // the channel should sends the user name in the 'From' object - var userName = turnContext.Activity.From.Name; + // the channel should sends the user name in the 'From' object + var userName = turnContext.Activity.From.Name; - await turnContext.SendActivityAsync($"You are seeing this message because this was your first message ever to this bot.", cancellationToken: cancellationToken); - await turnContext.SendActivityAsync($"It is a good practice to welcome the user and provide personal greeting. For example, welcome {userName}.", cancellationToken: cancellationToken); - } - else - { - // This example hardcodes specific utterances. You should use LUIS or QnA for more advance language understanding. - var text = turnContext.Activity.Text.ToLowerInvariant(); - switch (text) - { - case "hello": - case "hi": - await turnContext.SendActivityAsync($"You said {text}.", cancellationToken: cancellationToken); - break; - case "intro": - case "help": - await SendIntroCardAsync(turnContext, cancellationToken); - break; - default: - await turnContext.SendActivityAsync(WelcomeMessage, cancellationToken: cancellationToken); - break; - } - } + await turnContext.SendActivityAsync($"You are seeing this message because this was your first message ever to this bot.", cancellationToken: cancellationToken); + await turnContext.SendActivityAsync($"It is a good practice to welcome the user and provide personal greeting. For example, welcome {userName}.", cancellationToken: cancellationToken); } - - // Greet when users are added to the conversation. - // Note that all channels do not send the conversation update activity. - // If you find that this bot works in the emulator, but does not in - // another channel the reason is most likely that the channel does not - // send this activity. - else if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate) + else { - if (turnContext.Activity.MembersAdded != null) + // This example hardcodes specific utterances. You should use LUIS or QnA for more advance language understanding. + var text = turnContext.Activity.Text.ToLowerInvariant(); + switch (text) { - // Iterate over all new members added to the conversation - foreach (var member in turnContext.Activity.MembersAdded) - { - // Greet anyone that was not the target (recipient) of this message - // the 'bot' is the recipient for events from the channel, - // turnContext.Activity.MembersAdded == turnContext.Activity.Recipient.Id indicates the - // bot was added to the conversation. - if (member.Id != turnContext.Activity.Recipient.Id) - { - await turnContext.SendActivityAsync($"Hi there - {member.Name}. {WelcomeMessage}", cancellationToken: cancellationToken); - await turnContext.SendActivityAsync(InfoMessage, cancellationToken: cancellationToken); - await turnContext.SendActivityAsync(PatternMessage, cancellationToken: cancellationToken); - } - } + case "hello": + case "hi": + await turnContext.SendActivityAsync($"You said {text}.", cancellationToken: cancellationToken); + break; + case "intro": + case "help": + await SendIntroCardAsync(turnContext, cancellationToken); + break; + default: + await turnContext.SendActivityAsync(WelcomeMessage, cancellationToken: cancellationToken); + break; } } - else - { - // Default behavior for all other type of activities. - await turnContext.SendActivityAsync($"{turnContext.Activity.Type} activity detected"); - } - - // save any state changes made to your state objects. await _welcomeUserStateAccessors.UserState.SaveChangesAsync(turnContext); } - - /// - /// Sends an adaptive card greeting. - /// - /// A containing all the data needed - /// for processing this conversation turn. - /// (Optional) A that can be used by other objects - /// or threads to receive notice of cancellation. - /// A task that represents the work queued to execute. + private static async Task SendIntroCardAsync(ITurnContext turnContext, CancellationToken cancellationToken) { var response = turnContext.Activity.CreateReply(); diff --git a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserState.cs b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserState.cs index b346959af9..538c23f0b5 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserState.cs +++ b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserState.cs @@ -3,17 +3,13 @@ namespace Microsoft.BotBuilderSamples { - /// - /// Stores User Welcome state for the conversation. - /// Stored in and - /// backed by . - /// + // Stores User Welcome state for the conversation. + // Stored in "Microsoft.Bot.Builder.ConversationState" and + // backed by "Microsoft.Bot.Builder.MemoryStorage". + public class WelcomeUserState { - /// - /// Gets or sets whether the user has been welcomed in the conversation. - /// - /// The user has been welcomed in the conversation. + // Gets or sets whether the user has been welcomed in the conversation. public bool DidBotWelcomeUser { get; set; } = false; } } diff --git a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserStateAccessors.cs b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserStateAccessors.cs index 8c60f0be7e..dbc2e2d5fd 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserStateAccessors.cs +++ b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserStateAccessors.cs @@ -3,44 +3,31 @@ using System; using Microsoft.Bot.Builder; - +using Microsoft.Extensions.Logging; namespace Microsoft.BotBuilderSamples { - /// - /// This class holds a set of accessors (to specific properties) that the bot uses to access - /// specific data. These are created as singleton via DI. - /// + // This class holds a set of accessors (to specific properties) that the bot uses to access + // specific data. These are created as singleton via DI. public class WelcomeUserStateAccessors { - /// - /// Initializes a new instance of the class. - /// Contains the and associated . - /// - /// The state object that stores the counter. + // Initializes a new instance of the "WelcomeUserStateAccessors class. + // Contains the "UserState" and associated "IStatePropertyAccessor{T}". + // "userState" is the state object that stores the user data. public WelcomeUserStateAccessors(UserState userState) - { - UserState = userState ?? throw new ArgumentNullException(nameof(userState)); + { + UserState = userState ?? throw new ArgumentNullException(nameof(userState)); } - /// - /// Gets the name used for the accessor. - /// - /// Accessors require a unique name. - /// The accessor name for the WelcomeUser state. + // Gets the "IStatePropertyAccessor{T}" name used for the "BotBuilderSamples.WelcomeUserState" accessor. + // Accessors require a unique name. + // The value is the accessor name for the WelcomeUser state public static string WelcomeUserName { get; } = $"{nameof(WelcomeUserStateAccessors)}.WelcomeUserState"; - - /// - /// Gets or sets the for DidBotWelcome. - /// - /// - /// The accessor stores if the bot has welcomed the user or not. - /// + + // Gets or sets the "IStatePropertyAccessor{T}" for DidBotWelcome. + // The accessor stores if the bot has welcomed the user or not. public IStatePropertyAccessor WelcomeUserState { get; set; } - /// - /// Gets the object for the conversation. - /// - /// The object. + // Gets the "UserState" object for the conversation. public UserState UserState { get; } } } diff --git a/samples/csharp_dotnetcore/03.welcome-user/appsettings.json b/samples/csharp_dotnetcore/03.welcome-user/appsettings.json index 4b41c5c606..862e8fe8f6 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/appsettings.json +++ b/samples/csharp_dotnetcore/03.welcome-user/appsettings.json @@ -1,4 +1,4 @@ { - "botFilePath": "welcome-user.bot", - "botFileSecret": "" + "MicrosoftAppId": "", + "MicrosoftAppPassword": "" } \ No newline at end of file From 618f39970a4a5ff4fc47cfb1a5f479853c8afc41 Mon Sep 17 00:00:00 2001 From: John Taylor Date: Tue, 12 Mar 2019 14:45:43 -0700 Subject: [PATCH 2/2] drop Accessors class --- .../03.welcome-user/WelcomeUserBot.cs | 19 ++++------- .../WelcomeUserStateAccessors.cs | 33 ------------------- 2 files changed, 6 insertions(+), 46 deletions(-) delete mode 100644 samples/csharp_dotnetcore/03.welcome-user/WelcomeUserStateAccessors.cs diff --git a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs index ff9822b9c7..2e4e8e3e0a 100644 --- a/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs +++ b/samples/csharp_dotnetcore/03.welcome-user/WelcomeUserBot.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder; @@ -39,16 +38,12 @@ of the 'ConversationUpdate' event depends on the channel. You can to user, explaining what your bot can do. In this example, the bot handles 'hello', 'hi', 'help' and 'intro. Try it now, type 'hi'"; - // The bot state accessor object. Use this to access specific state properties. - private WelcomeUserStateAccessors _welcomeUserStateAccessors; - private UserState _userState; + private BotState _userState; // Initializes a new instance of the "WelcomeUserBot" class. public WelcomeUserBot(UserState userState) { _userState = userState; - _welcomeUserStateAccessors = new WelcomeUserStateAccessors(userState); - _welcomeUserStateAccessors.WelcomeUserState = _userState.CreateProperty(WelcomeUserStateAccessors.WelcomeUserName); } @@ -72,16 +67,12 @@ protected override async Task OnMembersAddedAsync(IList membersA protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) { - var didBotWelcomeUser = await _welcomeUserStateAccessors.WelcomeUserState.GetAsync(turnContext, () => new WelcomeUserState()); - - WelcomeUserState welcomeUserState = await _welcomeUserStateAccessors.WelcomeUserState.GetAsync(turnContext, () => new WelcomeUserState()); + var welcomeUserStateAccessor = _userState.CreateProperty(nameof(WelcomeUserState)); + var didBotWelcomeUser = await welcomeUserStateAccessor.GetAsync(turnContext, () => new WelcomeUserState()); if (didBotWelcomeUser.DidBotWelcomeUser == false) { didBotWelcomeUser.DidBotWelcomeUser = true; - // Update user state flag to reflect bot handled first user interaction. - await _welcomeUserStateAccessors.WelcomeUserState.SetAsync(turnContext, didBotWelcomeUser); - await _welcomeUserStateAccessors.UserState.SaveChangesAsync(turnContext); // the channel should sends the user name in the 'From' object var userName = turnContext.Activity.From.Name; @@ -108,7 +99,9 @@ protected override async Task OnMessageActivityAsync(ITurnContext WelcomeUserState { get; set; } - - // Gets the "UserState" object for the conversation. - public UserState UserState { get; } - } -}