简体   繁体   English

如何使用DirectLine通道在Azure表存储中存储和检索Bot数据?

[英]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已过时,我提到这个替换stateclientAzure Table storage However, I'm not able to understand how can I store the above data in the Table Storage . 但是,我不明白如何将以上数据Table StorageTable 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.

相关问题 对话总是在 Directline BOT 频道 websocket 中重新开始,如何保持畅通? - Conversation always restarts in Directline BOT channel websocket, how to keep it flowing? 如何在日期和时间之间从azure表存储中检索数据 - How to retrieve data from azure table storage between date and time Bot框架Directline对话数据 - Bot framework directline conversation data 如何在隔离存储文件中存储和检索数据? - How to store and retrieve data in Isolated Storage File? 为什么我无法在Skype通道的Azure表中保存和检索机器人数据? - Why I can't save and retrieve bot data in Azure Tables in Skype channel? 如何通过 Microsoft Bot Framework 将记录插入 Azure 表存储? - How to insert records to Azure Table Storage via Microsoft Bot Framework? 将查询字符串参数传递给直线通道Bot Framework - Passing query string parameters to directline channel Bot Framework 如何在 Azure 表存储中使用 RowKey 或时间戳检索最新记录 - How to retrieve latest record using RowKey or Timestamp in Azure Table storage 对 Azure 表存储的检索表操作进行单元测试 - Unit Testing a Retrieve TableOperation for Azure Table Storage Microsoft bot 框架 - Bot 通道注册。 无法将录制的视频从 Skype 保存到 Azure 存储帐户 - Microsoft bot framework - Bot channel Registration. Unable to save the recorded video from skype to Azure storage account
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM