0
votes

I have a problem with the Azure Table Storage. What I'm trying to achieve is saving the ChangeToken of the SharePoint list in order to use the webhooks properly.

Here is the code:

public class TablesHelper
{
    private static readonly string TokenTableName = "TokenTable";

    public static async Task<ListChangeToken> GetChangeTokenForListAsync(string listId)
    {
        var retrieveOperation = TableOperation.Retrieve<ListChangeToken>("Lists", listId, new List<string>() { "ChangeToken" });
        var tableReference = await GetTableReferenceAsync(TokenTableName);
        var tableResult = await tableReference.ExecuteAsync(retrieveOperation);
        if(tableResult.Result != null)
        {
            return tableResult.Result as ListChangeToken;
        }
        return null;
    }

    public static async Task SaveChangeTokenForListAsync(ListChangeToken changeToken)
    {
        var insertOperation = TableOperation.Insert(changeToken);
        var tableReference = await GetTableReferenceAsync(TokenTableName);
        var result = await tableReference.ExecuteAsync(insertOperation);
    }

    private static async Task<CloudTable> GetTableReferenceAsync(string tableName)
    {
        var storageAccount = CloudStorageAccount.Parse(ConfigurationHelper.CloudStorage);
        var tableClient = storageAccount.CreateCloudTableClient();
        var reference = tableClient.GetTableReference(tableName);
        await reference.CreateIfNotExistsAsync();
        return reference;
    }
}

The ListChangeToken class:

public class ListChangeToken : TableEntity
{
    public ListChangeToken(string listId, string changeToken)
    {
        this.PartitionKey = "Lists";
        this.RowKey = listId;
        this.ChangeToken = changeToken;
    }

    public ListChangeToken() { }

    public string ChangeToken { get; set;}
}

As per request, the function calling TablesHelper:

 [FunctionName("EventHandler")]
    public static async Task Run([QueueTrigger("events", Connection = "CloudStorage")]string myQueueItem, TraceWriter log)
    {
        var notificationGroup = Newtonsoft.Json.JsonConvert.DeserializeObject<NotificationGroup>(myQueueItem);
        var contextHelper = new ContextHelper();
        foreach (var notification in notificationGroup.Value)
        {
            UriBuilder uriBuilder = new UriBuilder();
            uriBuilder.Scheme = "https";
            uriBuilder.Host = ConfigurationHelper.TenantDomain;
            uriBuilder.Path = notification.SiteUrl;
            using (var ctx = contextHelper.GetAppOnlyContext(uriBuilder.ToString()))
            {
                //Read change token
                var currentChangeToken = await TablesHelper.GetChangeTokenForListAsync(notification.Resource);
                if(currentChangeToken == null)
                {
                    log.Error($"No change token found for list {notification.Resource}. This is a NO GO. Please use the '/api/Setup' function.");
                }
                var listId = Guid.Parse(notification.Resource);
                var changes = await CSOMHelper.GetListItemChangesAsync(ctx, listId, currentChangeToken.ChangeToken);
                if(changes.Count > 0)
                {
                    var lastChange = changes[changes.Count - 1];
                    //Save the last change token
                    var changeTokenValue = lastChange.ChangeToken.StringValue;
                    await TablesHelper.SaveChangeTokenForListAsync(new ListChangeToken(
                            notification.Resource,
                            changeTokenValue
                        ));
                    await HandleChanges(ctx, changes);
                }
            }
        }
        log.Info($"C# Queue trigger function processed: {myQueueItem}");
    }

The problem is that always, when using the "GetChangeTokenForListAsync" the Entity is received properly, but the .ChangeToken property is always null. It is also not visible when browsing with the Azure Storage Explorer. What am I doing wrong here?

1
Can you post the code that make the calls to the TablesHelper class?Peter Bons
As requested, have updated the code:)Ciamas
What kind of value would be in changeTokenValue . I've tried it with a simple value of d and it just works, so the code in TablesHelper and ListChangeToken is fine.Peter Bons
Maybe it has then something to do with the AzureStorage Emulator? It is a string representing the change token in SharePoint list. This is the way it could be constructed: string.Format("1;3;{0};{1};-1", list.Id.ToString(), DateTime.Now.AddDays(-2).ToUniversalTime().Ticks.ToString());Ciamas
Yep, that's the case. It has been save while using the "live" Azure.Ciamas

1 Answers

0
votes

The issue is related to the Azure Storage Emulator (V. 5.7.0.0). The same code works perfectly when working with the "live" Azure.