Search code examples
botframeworkazure-cosmosdbazure-storage-account

How to get cosmosDB or storageAccount connection in DebugActivityLogger of botframework C#


I want to save my conversation history to Azure Cosmos DB or storageAccount.

  1. About Azure Cosmos DB

It seems really easy to use IActivityLogger. But I don't know how could I get the DB connection which is connected in Global.asax.cs. Or it's better to get it again in IActivityLogger?

  1. About storageAccount

According this, SDK also provides a way to save conversation history using storageAccount. But the Activity has been compressed. I want to save my real conversation[JSON] which is not compressed, to storageAccount.

I'm trying to insert a row to Azure table storage which has compressed data. But Activity0 is always null.

public class ActivityEntity : TableEntity
    {
        /// <summary>
        /// Empty constructor.
        /// </summary>
        public ActivityEntity()
        { }

        /// <summary>
        /// Construct from an IActivity.
        /// </summary>
        /// <param name="activity"></param>
        public ActivityEntity(byte[] Activity)
        {
            PartitionKey = "111";
            RowKey = "11";
            From = "111";
            Recipient = "111";
            Activity0 = Activity;
            Version = 3.0;
        }

        /// <summary>
        /// Version number for the underlying activity.
        /// </summary>
        public double Version { get; set; }

        /// <summary>
        /// Channel identifier for sender.
        /// </summary>
        public string From { get; set; }

        /// <summary>
        /// Channel identifier for receiver.
        /// </summary>
        public string Recipient { get; set; }

        /// <summary>
        /// Logged activity.
        /// </summary>
        [IgnoreProperty]
        public byte[] Activity0 { get; set; }

        /// <summary>
        /// Generate a partition key given <paramref name="channelId"/> and <paramref name="conversationId"/>.
        /// </summary>
        /// <param name="channelId">Channel where activity happened.</param>
        /// <param name="conversationId">Conversation where activity happened.</param>
        /// <returns>Partition key.</returns>
        public static string GeneratePartitionKey(string channelId, string conversationId)
        {
            return $"{channelId}|{conversationId}";
        }

        /// <summary>
        /// Generate row key for ascending <paramref name="timestamp"/>.
        /// </summary>
        /// <param name="timestamp">Timestamp of activity.</param>
        /// <returns></returns>
        public static string GenerateRowKey(DateTime timestamp)
        {
            return $"{timestamp.Ticks:D19}";
        }

    }




     class Program
    {
        public static object CloudConfigurationManager { get; private set; }

        static void Main(string[] args)
        {

            CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=storagetesthuafu;AccountKey=iQ0EZexm3wbpWZqly2HtVH0/CZKRyMY9l2b0g20AQkUz7BX0BFLuBinMyYLe8Ow/zOA7vJqAMSxSHllT3JTL2g==;EndpointSuffix=core.windows.net");

            // Create the table client.
            CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

            // Create the CloudTable object that represents the "TemperatureData" table.
            CloudTable table = tableClient.GetTableReference("messagelog");



            TableQuery<BotDataRow> query = new TableQuery<BotDataRow>();
            var data = table.ExecuteQuery(query);
            var dataarry = data.ToArray();


            var aa = dataarry.First();
            var activity = aa.Activity0;
            var after = Decompress(activity);


            CloudTable tableTEST = tableClient.GetTableReference("messagelog");


            byte[] bb = Encoding.UTF8.GetBytes(after);
            ActivityEntity customer4 = new ActivityEntity(bb);

            // Create the InsertOrReplace TableOperation.
            TableOperation insertOrReplaceOperation = TableOperation.InsertOrReplace(customer4);

            // added to the table.
            table.Execute(insertOrReplaceOperation);
        }

Solution

  • Creating an IActivityLogger implementation that uses DocumentDb doesn't require much code. Here's an example using the Azure Cosmos DB Emulator:

    class DocumentDbActivityLogger : IActivityLogger
    {
        const string DbKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
        const string DbUri = "https://localhost:8081";
        const string DbId = "ActivityLogsDb";
        const string CollectionId = "ActivityLogsColleciton";
    
        async Task IActivityLogger.LogAsync(IActivity activity)
        {
            try
            {
                var message = activity.AsMessageActivity();
                if (message != null)
                {
                    using (var documentClient = new DocumentClient(new Uri(DbUri), DbKey))
                    {
                        await documentClient.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(DbId, CollectionId), message);
                    }
                }
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Print(e.ToString());
            }
        }
    }
    

    Then, register it in Global.asax.cs:

    Conversation.UpdateContainer(builder =>
    {
         builder.RegisterType<DocumentDbActivityLogger>().AsImplementedInterfaces().InstancePerDependency();
    }
    

    enter image description here