[英]How to store & retrieve Bot Data in Azure Table storage with directLine channel?
I'm using Microsoft Bot Framework
with directLine
channel. 我正在使用带有
directLine
通道的Microsoft Bot Framework
。 My Bot is a part of company's customer portal from where I fetch some user information and store it in BotState
using stateClient
as shown below 我的Bot是公司客户门户网站的一部分,从那里我可以获取一些用户信息,并使用
stateClient
将其存储在BotState
中,如下所示
public ActionResult Index()
{
var userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
GetTokenViaBootStrap().Wait();
var botCred = new MicrosoftAppCredentials(
ConfigurationManager.AppSettings["MicrosoftAppId"],
ConfigurationManager.AppSettings["MicrosoftAppPassword"]);
var stateClient = new StateClient(botCred);
BotState botState = new BotState(stateClient);
BotData botData = new BotData(eTag: "*");
botData.SetProperty<string>("UserName", result.UserInfo.GivenName + " " + result.UserInfo.FamilyName);
botData.SetProperty<string>("Email", result.UserInfo.DisplayableId);
botData.SetProperty<string>("GraphAccessToken", UserAccessToken);
botData.SetProperty<string>("TokenExpiryTime", result.ExpiresOn.ToString());
stateClient.BotState.SetUserDataAsync("directline", userId, botData).Wait();
var UserData = new UserInformationModel
{
UserId = userId,
UserName = result.UserInfo.GivenName + " " + result.UserInfo.FamilyName
};
return View(UserData);
}
As its a directLine
channel, I'm connecting my bot using secret in javascript as shown below: 作为其
directLine
频道,我正在使用javascript中的secret连接我的机器人,如下所示:
BotChat.App({
bot: { id: 'my_bot_id', name: 'my_bot_id' },
resize: 'detect',
sendTyping: true, // defaults to false. set to true to send 'typing' activities to bot (and other users) when user is typing
user: { id: UserData.UserId},
directLine: {
secret: "my_bot_secret"
}
}, document.getElementById('my_bot_id'));
I'm accessing user information data in Node js Bot captured in MVC site as shown below: 我正在访问MVC站点中捕获的Node js Bot中的用户信息数据,如下所示:
function sessionUserCapture(session) {
switch (session.message.address.channelId) {
case 'skypeforbusiness':
// some code
break;
case 'directline':
userName= session.userData.UserName;
userEmail= session.userData.Email;
//some code
break;
case 'slack':
// some code
}
}
I referred Microsoft's Save state data from Manage state data for above code and then I used userData
available in the session
to access this data in my Node.JS
Bot. 我从上面的代码的“ 管理状态数据”中引用了Microsoft的“ 保存状态数据” ,然后使用了
session
可用的userData
来访问Node.JS
Bot中的该数据。
As the StateClient is Deprecated, I referred this to replace stateclient
with Azure Table storage
. 作为StateClient已过时,我提到这个替换
stateclient
与Azure Table storage
。 However, I'm not able to understand how can I store the above data in the Table Storage
. 但是,我不明白如何将以上数据
Table Storage
在Table Storage
。
Can anyone suggest any article which I can refer to solve this issue? 谁能建议我可以参考的任何文章来解决此问题?
My Bot is in NodeJs
and the I'm using directLine
channel in a C# MVC application
. 我的机器人在
NodeJs
,我在C# MVC application
使用directLine
通道。
One option is to use the Microsoft Azure Storage Client Library for .NET, as explained in the answer here: How to retrieve Saved Conversation Data in Azure (Tablelogger) Just make sure to follow the exact same PartitionKey strategy as is followed by the TableBotDataStore class, and serialize the data field correctly. 一种选择是使用Microsoft .NET的Microsoft Azure存储客户端库 ,如此处答案所示: 如何在Azure中检索已保存的会话数据(Tablelogger)只需确保遵循与TableBotDataStore类遵循的完全相同的PartitionKey策略,并正确序列化数据字段。
-- Edit: I tested this out, and it does in fact work as expected. -编辑:我测试了一下,实际上它确实按预期工作。
public class WebChatController : Controller
{
public ActionResult Index()
{
var connectionString = ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString;
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("BotStore");
string userId = Guid.NewGuid().ToString();
TableQuery<BotDataRow> query = new TableQuery<BotDataRow>().Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, userId));
var dataRow = table.ExecuteQuery(query).FirstOrDefault();
if(dataRow != null)
{
dataRow.Data = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
UserName = "This user's name",
Email = "whatever@email.com",
GraphAccessToken = "token",
TokenExpiryTime = DateTime.Now.AddHours(1)
});
dataRow.Timestamp = DateTimeOffset.UtcNow;
table.Execute(TableOperation.Replace(dataRow));
}
else
{
var row = new BotDataRow(userId, "userData");
row.Data = Newtonsoft.Json.JsonConvert.SerializeObject(new
{
UserName = "This user's name",
Email = "whatever@email.com",
GraphAccessToken = "token",
TokenExpiryTime = DateTime.Now.AddHours(1)
});
row.Timestamp = DateTimeOffset.UtcNow;
table.Execute(TableOperation.Insert(row));
}
var vm = new WebChatModel();
vm.UserId = userId;
return View(vm);
}
public class BotDataRow : TableEntity
{
public BotDataRow(string partitionKey, string rowKey)
{
this.PartitionKey = partitionKey;
this.RowKey = rowKey;
}
public BotDataRow() { }
public bool IsCompressed { get; set; }
public string Data { get; set; }
}
}
In the node bot: 在节点漫游器中:
'use strict';
const builder = require('botbuilder');
const restify = require('restify');
var azure = require('botbuilder-azure');
var tableName = 'BotStore';
var azureTableClient = new azure.AzureTableClient(tableName,'accountname','accountkey');
var tableStorage = new azure.AzureBotStorage({ gzipData: false }, azureTableClient);
const connector = new builder.ChatConnector({
appId: process.env.MicrosoftAppId,
appPassword: process.env.MicrosoftAppPassword
});
const server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3979, () => {
console.log(`${server.name} listening to ${server.url}`);
});
server.post('/api/messages', connector.listen());
var bot = new builder.UniversalBot(connector)
.set('storage', tableStorage);;
bot.dialog('/',
[
function (session){
var data = session.userData;
}
]);
The code you are using is using the deprecated default state and will not work. 您使用的是使用过时的默认状态,将无法正常工作的代码。 In order to accomplish what you would like it depends on where you are in your code.
为了完成您想要的操作,这取决于您在代码中的位置。 The deciding factor is if you have access to the
context
object or not. 决定因素是您是否有权访问
context
对象。
For example if you are in the MessagesController
you will not have access to the context object and your code might look like this: 例如,如果您在
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());
}
}
then to get the data: 然后获取数据:
userData.GetProperty<string>("key 1");
The other situation would be if you did have access to the context object like in a Dialog
for example, your code might look like this: 另一种情况是,如果您确实确实可以访问上下文对象,例如在
Dialog
中,则您的代码可能如下所示:
context.UserData.SetValue("key 1", "value1");
context.UserData.SetValue("key 2", "value2");
then to get the data: 然后获取数据:
context.UserData.GetValue<string>("key 1");
Have you configured your bot to connect to Azure Table Storage in Global.asax.cs, instead of the deprecated default state? 您是否已将漫游器配置为连接到Global.asax.cs中的Azure表存储,而不是已弃用的默认状态?
I have written a blog post with full details on how to move your bot's state to Azure Table Storage which you should review here 我写了一篇博客文章,其中详细介绍了如何将您的机器人状态转移到Azure表存储,您应该在此处查看
protected void Application_Start()
{
Conversation.UpdateContainer(
builder =>
{
builder.RegisterModule(new AzureModule(Assembly.GetExecutingAssembly()));
// Using Azure Table for storage
var store = new TableBotDataStore(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
builder.Register(c => store)
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.AsSelf()
.SingleInstance();
});
GlobalConfiguration.Configure(WebApiConfig.Register);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.