Wednesday, July 26, 2017

Iterative approach for making repeatable Sharepoint Online CSOM and Graph API calls more robust

In one of our project we used Azure web job which ran by scheduler and performed some periodic actions. They included Sharepoint Online CSOM calls for updating list item in Sharepoint list and Graph API calls for getting members of Azure AD group. From time to time these calls failed randomly, e.g. attempt to update list item via CSOM failed with “Version conflict” exception and Graph API calls failed with service exception without any clear error message. Both APIs are continuously evolved and calls (especially repeated calls which run frequently) may still fail with such inconsistent errors.

As workaround to make process more robust the following approach was used: make API calls in several attempts. If 1st attempt failed, wait some time and repeat call again – max number of attempts is also specified. Here is the code which demonstrates the idea:

   1: private static void UpdateListItemSafely(ClientContext ctx, List list, ListItem item,
   2:     List<User> users, out bool isError)
   3: {
   4:     isError = false;
   5:     UpdateListItem(ctx, list, item, users, out isError);
   6:     if (isError)
   7:     {
   8:         int numOfAttempts = 4;
   9:         for (int i = 0; i < numOfAttempts; i++)
  10:         {
  11:             Thread.Sleep(1000);
  12:             UpdateListItem(ctx, list, item, users, out isError);
  13:             if (!isError)
  14:             {
  15:                 break;
  16:             }
  17:         }
  18:     }
  19: }
  20:  
  21: private static void UpdateListItem(ClientContext ctx, List list, ListItem item,
  22:     List<User> users, out bool isError)
  23: {
  24:     isError = false;
  25:     try
  26:     {
  27:         var listItem = list.GetItemById(item.Id);
  28:         ctx.Load(listItem);
  29:         ctx.ExecuteQueryRetry();
  30:  
  31:         listItem["Users"] = users != null ?
  32:             users.Select(u => new FieldUserValue { LookupId = u.Id }).ToArray() :
  33:             new FieldUserValue[0];
  34:         listItem.Update();
  35:         ctx.ExecuteQueryRetry();
  36:     }
  37:     catch (Exception x)
  38:     {
  39:         isError = true;
  40:     }
  41: }

Here we make 5 attempts to update list item – set users to User field type with multiple values (lines 21-41) with 1 sec delay between attempts (lines 5-18). In code we use it like this:

   1: bool isError = false;
   2: UpdateListItemSafely(ctx, list, item, users, out isError);
   3: if (isError)
   4: {
   5:     // error handling
   6: }

And similar approach was used for Graph API calls. After that web job runs became much more robust.

Thursday, July 6, 2017

Sharepoint MVP 2017

Hello dear readers of my blog. I’m glad to tell that became Sharepoint MVP 2017 and I’m happy that my contribution to community’s life help developers and IT professionals all over the world in their every day work. Based on my personal experience in IT (which is almost 14 years already) I would say that sharing knowledge and real-world solutions in internet is the most helpful thing which IT professionals may do for each other. Besides technical blogging I also continue to contribute in Camlex open source project which helps Sharepoint developers to build dynamic CAML queries (btw Codeplex is shutting down this year so Camlex will have new home on github soon. I will write separate post about that) and answer questions in MSDN blogs. I personally think that community related work is very important and will continue to do it also in future. And I would like to give special thanks to MS for this high recognition.