private bool InitializeSkill(DialogContext dc) { if (dc.ActiveDialog.State.ContainsKey(ActiveSkillStateKey)) { var skill = dc.ActiveDialog.State[ActiveSkillStateKey] as SkillService; var cosmosDbOptions = _cosmosDbOptions; cosmosDbOptions.CollectionId = skill.Name; var cosmosDbStorage = new CosmosDbStorage(cosmosDbOptions); var conversationState = new ConversationState(cosmosDbStorage); try { var skillType = Type.GetType(skill.Assembly); _activatedSkill = (IBot)Activator.CreateInstance(skillType, conversationState, $"{skill.Name}State", skill.Configuration); } catch (Exception e) { var message = $"Skill ({skill.Name}) Type could not be created."; throw new InvalidOperationException(message, e); } _inProcAdapter = new InProcAdapter { OnTurnError = async(context, exception) => { await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : exception.Message)); await context.SendActivityAsync(context.Activity.CreateReply($"Sorry, something went wrong trying to communicate with the skill. Please try again.")); await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Skill Error: {exception.Message} | {exception.StackTrace}")); _telemetryClient.TrackException(exception); }, }; _inProcAdapter.Use(new EventDebuggerMiddleware()); _inProcAdapter.Use(new AutoSaveStateMiddleware(conversationState)); skillInitialized = true; } else { // No active skill? } return(skillInitialized); }
private async Task InitializeSkill(DialogContext dc) { try { var skillDefinition = dc.ActiveDialog.State[ActiveSkillStateKey] as SkillDefinition; var skillConfiguration = _skills[skillDefinition.Id]; IStorage storage; if (skillConfiguration.CosmosDbOptions != null) { var cosmosDbOptions = skillConfiguration.CosmosDbOptions; cosmosDbOptions.CollectionId = skillDefinition.Name; storage = new CosmosDbStorage(cosmosDbOptions); } else { storage = new MemoryStorage(); } // Initialize skill state var userState = new UserState(storage); var conversationState = new ConversationState(storage); // Create skill instance try { var skillType = Type.GetType(skillDefinition.Assembly); _activatedSkill = (IBot)Activator.CreateInstance(skillType, skillConfiguration, conversationState, userState, _telemetryClient, null, true); } catch (Exception e) { var message = $"Skill ({skillDefinition.Name}) could not be created."; throw new InvalidOperationException(message, e); } _inProcAdapter = new InProcAdapter { // set up skill turn error handling OnTurnError = async(context, exception) => { await context.SendActivityAsync(context.Activity.CreateReply(CommonResponses.ErrorMessage_SkillError)); await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Skill Error: {exception.Message} | {exception.StackTrace}")); // Log exception in AppInsights skillConfiguration.TelemetryClient.TrackException(exception); }, }; _inProcAdapter.Use(new EventDebuggerMiddleware()); _inProcAdapter.Use(new SetLocaleMiddleware(dc.Context.Activity.Locale ?? "en-us")); _inProcAdapter.Use(new AutoSaveStateMiddleware(userState, conversationState)); _skillInitialized = true; } catch { // something went wrong initializing the skill, so end dialog cleanly and throw so the error is logged _skillInitialized = false; await dc.EndDialogAsync(); throw; } }
private bool InititializeSkill(DialogContext dc) { if (dc.ActiveDialog.State.ContainsKey(ActiveSkillStateKey)) { var skill = dc.ActiveDialog.State[ActiveSkillStateKey] as SkillRegistration; var cosmosDbOptions = _cosmosDbOptions; // Isolate from the main Bot's storage and put skill state into it's own collection cosmosDbOptions.CollectionId = skill.Name; // The Skill state will be stored in our parent Bot storage var cosmosDbStorage = new CosmosDbStorage(cosmosDbOptions); var conversationState = new ConversationState(cosmosDbStorage); // Reflection is used to enable dynamic lookup of Skills and keep it configuration based // A configuration driven approach is elegant but Reflection is pretty heavyweight, explore DI try { // Create the skill and crucially pass the provided Conversation State in through a new constructor specific to skill activation var skillType = Type.GetType(skill.Assembly); activatedSkill = (IBot)Activator.CreateInstance(skillType, conversationState, $"{skill.Name}State", skill.Configuration); } catch (Exception e) { var message = $"Skill ({skill.Name}) Type could not be created."; throw new InvalidOperationException(message, e); } // Initialise the Adapter and Middlware used to invoke Skills. We leverage the same Storage account as configured by the parent Bot otherwise the Parent Bot would need // To know about all of the storage information for each skill and cause an explosion of Skill state stores. This approach keeps things simple and ensures Skill state is owned/managed // By the parent Bot which feels the right way forward. // We create our own "collection" for Skills state. inProcAdapter = new InProcAdapter { OnTurnError = async(context, exception) => { await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : exception.Message)); await context.SendActivityAsync(context.Activity.CreateReply($"Sorry, something went wrong trying to communicate with the skill. Please try again.")); await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Skill Error: {exception.Message} | {exception.StackTrace}")); _telemetryClient.TrackException(exception); }, }; inProcAdapter.Use(new EventDebuggerMiddleware()); // TODO: Send property bag across to skill from registration inProcAdapter.Use(new AutoSaveStateMiddleware(conversationState)); skillInitialized = true; } else { // No active skill? } return(skillInitialized); }
private async Task InitializeSkill(DialogContext dc) { try { IStorage storage; if (_skillConfiguration.CosmosDbOptions != null) { var cosmosDbOptions = _skillConfiguration.CosmosDbOptions; cosmosDbOptions.CollectionId = _skillDefinition.Name; storage = new CosmosDbStorage(cosmosDbOptions); } else { storage = new MemoryStorage(); } // Initialize skill state var userState = new UserState(storage); var conversationState = new ConversationState(storage); // Create skill instance try { var skillType = Type.GetType(_skillDefinition.Assembly); // Have to use refined BindingFlags to allow for optional parameters on constructors. _activatedSkill = (IBot)Activator.CreateInstance( skillType, BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding, default(Binder), new object[] { _skillConfiguration, _endpointService, conversationState, userState, _proactiveState, _telemetryClient, _backgroundTaskQueue, true }, CultureInfo.CurrentCulture); } catch (Exception e) { var message = $"Skill ({_skillDefinition.Name}) could not be created."; throw new InvalidOperationException(message, e); } _inProcAdapter = new InProcAdapter { // set up skill turn error handling OnTurnError = async(context, exception) => { await context.SendActivityAsync(_responseManager.GetResponse(CommonResponses.ErrorMessage_SkillError)); await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Skill Error: {exception.Message} | {exception.StackTrace}")); // Log exception in AppInsights _telemetryClient.TrackExceptionEx(exception, context.Activity); }, BackgroundTaskQueue = _backgroundTaskQueue }; _inProcAdapter.Use(new EventDebuggerMiddleware()); _inProcAdapter.Use(new SetLocaleMiddleware(dc.Context.Activity.Locale ?? "en-us")); _inProcAdapter.Use(new AutoSaveStateMiddleware(userState, conversationState)); _skillInitialized = true; } catch { // something went wrong initializing the skill, so end dialog cleanly and throw so the error is logged _skillInitialized = false; await dc.EndDialogAsync(); throw; } }