Kylie Bot Part 11 - Undocumented Features
During the course of any Dynamics 365 Customer Engagement project, you are likely to experience these "undocumented features". More currently referred to as bugs, they always seem to crop up at the most inopportune times. The Kylie Bot project is no different and suffers from the same bugs.
To be specific, there were issues with persisting the user object across the conversations we were facilitating with Kylie Bot. The cause of these issues was that the Internet Information Services (IIS) apppool that we are hosting the Kylie Bot website on, was being recycled every 30 minutes by Azure. This behaviour is to be expected as the website needs to be continually maintained by the service containers that it is hosted in (the apppools). An apppool is typically recycled to ensure garbage collection happens, the cache of the website is refreshed and certain resources are released to be consumed again as necessary. All-in-all, the recycling on an apppool is a good thing but it presented a challenge for how to persist the User object in our project.
The answer? Read the documentation. This is something that we should all spend more time on, but I doubt that many of us will. Regardless, having a quick browse through the Bot Framework's elements, I was quick to stumble upon the following article: Manage Bot State. Here, unsurprisingly, the answer was presented. There is a built-in mechanism to handle and store user data. This is great news, but why not just edit the settings of the apppool? Simple, using the framework as intended ensures ease of use, and more importantly, performance. Changing the apppool setting can be disastrous to performance and can lead to out dated information and functions being surfaced. To avoid this, we need to update several elements of the project to align with the bot state and userdata functionality.
Most of the changes happened in the MessagesController.cs class where we need to remove the old static User lists and replace them with the new versions. Important to note are the following lines which generate the bot state and userdata objects we need:
StateClient stateClient = activity.GetStateClient()
BotData userData = await stateClient.BotState.GetUserDataAsync(activity.ChannelId, activity.From.Id)
Most of the rest of the changes are in changing the list options with those supported by the userData options. Very simply, you can either get a simple property from the user data like this:
bool userCreated = userData.GetProperty<bool>("UserCreated")
Or, you can get a complex property as follows.
User user = userData.GetProperty<User>("User")
If you need to set a simple property, it can be done as follows:
A complex property is set as follows:
Remember that SetProperty changes will need to be committed back to the bot state object provided. The following line of code facilitates this:
await stateClient.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData)
A number of these changes also had to be made to the following classes:
Finally, some methods were moved from the MessageController.cs class to the BotHelper.cs class to keep things tidy.
One issue I did run into was that of the Bot Framework trying to commit certain changes automatically on my behalf. After a bit of head scratching, I worked out the following. Whenever you have an IDalogContext object available (typically in Dialogs), you will need to update the underlying data object of the userdata rather than the property itself. First, you will need to create the userdata object in a slightly different way, like this:
var userData = context.UserData
Following that, you can update the value you wish directly:
In this scenario, there is no need to commit the changes as the Bot Framework will do this on your behalf. Awesome, so what difference will you notice? None really. The underlying structure and functionality now just works as it should have in the first place.
I have provided the updated solution here and don't forget to check in your own code!
Look out for the next post where we start providing more content to Kylie Bot by making use of Azure Indexes.