I migrated to a Table Azure Provider for managing Microsoft bot framework state.
In my telemetry, I see dependencies call being made to my new Table Azure Storage however I still see a lot of calls being made to state.botframework.com and some have the usual random slow response time.
This does not seem normal as I would have expect all calls to be directed to my new private state provider:
Example: https://state.botframework.com/v3/botstate/facebook/users/999999999999
Example of call to new private state provider: https://xxxxxxxxxx.table.core.windows.net:443/botdata(PartitionKey='facebook:private',RowKey='XXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXXXXXX
Other potential relevant information:
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
//Register custom datastore
builder
.RegisterKeyedType<TableBotDataStore, IBotDataStore<BotData>>()
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.WithParameter((pi, c) => pi.Name == "connectionString",
(pi, c) =>
ConfigurationManager.ConnectionStrings["X"].ConnectionString)
.SingleInstance();
builder.RegisterAdapterChain<IBotDataStore<BotData>>
(
typeof(TableBotDataStore),
typeof(CachingBotDataStore)
)
.InstancePerLifetimeScope();
}
public static async Task CheckClientVersion(Activity activity)
{
StateClient stateClient = activity.GetStateClient();
BotData userData = stateClient.BotState.GetUserData(activity.ChannelId, activity.From.Id);
if (userData?.GetProperty<string>("version")?.CompareTo(Assembly.GetExecutingAssembly().GetName().Version.ToString()) != 0)
{
string[] result = await stateClient.BotState.DeleteStateForUserAsync(activity.ChannelId, activity.From.Id, CancellationToken.None);
userData = stateClient.BotState.GetUserData(activity.ChannelId, activity.From.Id);
userData.SetProperty<string>("version", Assembly.GetExecutingAssembly().GetName().Version.ToString());
await stateClient.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);
}
}
Is your second Code Snippet is that from a Dialog
or MessagesController
? the issue is you are using activity.GetStateClient
which Always calls the default state client rather than your own custom one.
In order to Accomplish what you want code similar to below must be used if you are manipulating state in the MessagesController
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
var message = activity as IMessageActivity;
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(message);
var userData = await botDataStore.LoadAsync(key, BotStoreType.BotUserData, CancellationToken.None);
userData.SetProperty("key 1", "value1");
userData.SetProperty("key 2", "value2");
await botDataStore.SaveAsync(key, BotStoreType.BotUserData, userData, CancellationToken.None);
await botDataStore.FlushAsync(key, CancellationToken.None);
}
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
}
To answer your follow up question:
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var token = new CancellationToken();
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(token);
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
botData.UserData.Clear();
botData.ConversationData.Clear();
botData.PrivateConversationData.Clear();
await botData.FlushAsync(token);
var botToUser = scope.Resolve<IBotToUser>();
await botToUser.PostAsync(message.CreateReply($"{timerMessage} Conversation aborted."));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With