6

I have multiple methods being called on different user actions which is using ClientContext. Creating it on every method execution was causing performance issue.

So I added it as static variable for re-usability, the performance improved with an average of 5seconds but then in some methods it start giving random issue of "Version conflict" on ExecuteQuery(). But if I remove the static and null check, then it get refreshed every time and performance becomes an issue

Is there any way to create one time object of this or at-least not on every call? And what is the default expiry of ClientContext?

Code for creating object of ClientContext:

    public class SPConnection
    {
    public static ClientContext SharepointClientContext { get; set; }
    public static ClientContext GetSharePointContext()
    {
        try
        {
            if (SharepointClientContext == null)
            {
                string appId = System.Configuration.ConfigurationManager.AppSettings["appId"];
                string appSecret = System.Configuration.ConfigurationManager.AppSettings["appSecret"];
                string siteUrl = System.Configuration.ConfigurationManager.AppSettings["siteUrl"];

                var authManager = new OfficeDevPnP.Core.AuthenticationManager();
                using (ClientContext clientContext = authManager.GetAppOnlyAuthenticatedContext(siteUrl, appId, appSecret))
                {
                    SharepointClientContext = clientContext;
                    return clientContext;
                }
            }
            else
                return SharepointClientContext;
        }
        catch (Exception ex)
        {
            iChange.Web.API.Authentication.SPConnection.InsertRecordToTableErrorLog("Mucebat:"+ex.Message, ex.StackTrace.ToString());
            throw ex;
        }

    }

Code for one of the method consuming it:

    public bool UpdateProfilePic(updateprofilepicmodel model)
    {
        using (ClientContext context = SPConnection.GetSharePointContext())
        {
            List list = context.Web.Lists.GetByTitle("Members");
            ListItemCreationInformation info = new ListItemCreationInformation();
            ListItem item = list.GetItemById(model.MemberId);

            item["ProfilePicture"] = model.ProfilepicUrl;
            item.Update();
            context.ExecuteQuery();
            return true;
        }

    }
Amna
  • 603
  • 7
  • 30

3 Answers3

1

Can you try using ExecuteQueryAsync in combination with async tasks for performance improvement? e.g.

     public async Task <bool> UpdateProfilePic(updateprofilepicmodel model)
{
    using (ClientContext context = SPConnection.GetSharePointContext())
    {
        List list = context.Web.Lists.GetByTitle("Members");
        ListItem item = list.GetItemById(model.MemberId);
        context.Load(item);
        Task t1 = context.ExecuteQueryAsync();
        await t1.ContinueWith((t) =>
            {
                item["ProfilePicture"] = model.ProfilepicUrl;
                item.Update();
                Task t2 = context.ExecuteQueryAsync();
            });

        await t2.ContinueWith((t) =>
            {
               // do some stuff here if needed
            });

        return true;
    }
}

P.S: i have not tested this code, but in case if this works for you

Muhammad Murad Haider
  • 1,357
  • 2
  • 18
  • 34
  • Yes it is one of the other things I am doing to boost performance. – Amna Feb 28 '20 at 09:30
  • Nice, please let me know about your results or update the post in case of success. I am more into using JSOM and this is very much possible there but have doubts about CSOM (.net). Following this question, and also upvoted this :) – Muhammad Murad Haider Feb 28 '20 at 09:39
0

You can try to Load the list item before update it. Modify the code as below to check if it works.

public bool UpdateProfilePic(updateprofilepicmodel model)
{
    using (ClientContext context = SPConnection.GetSharePointContext())
    {
        List list = context.Web.Lists.GetByTitle("Members");
        ListItem item = list.GetItemById(model.MemberId);
        context.Load(item);
        context.ExecuteQuery();
        item["ProfilePicture"] = model.ProfilepicUrl;
        item.Update();
        context.ExecuteQuery();
        return true;
    }
}

If the code above not works, you can enable the version of the "Members" list in list settings to check if the issue still exists.

LZ_MSFT
  • 4,079
  • 1
  • 8
  • 9
  • I can do that, but this is not the only place and calling context.ExecuteQuery(); multiple times in each will be an overhead. – Amna Feb 24 '20 at 09:54
0

You cannot use ClientContext as static object. In code you are writing your code in Using segment. ClientContext object will destroy once the execution of us using block is completed.

  • I am assigning it to another variable "SharepointClientContext " in using statement. And further using that public parameter. – Amna Feb 27 '20 at 09:59
  • Exactly. The client context you use is on stack and memory is allocated to it. When using statement is destroyed the memory is deallocated. Using is use to save the memory. – Muhammad Zeeshan Mahmood Feb 27 '20 at 17:42
  • Send me the exact code.and the list structure you are using to understand the problem – Muhammad Zeeshan Mahmood Feb 27 '20 at 17:46
  • It is the exact code and it will work fine for like hours and then start failing out of sudden. All the purpose was to use static ClientContext object in every method, but I guess that's not possible. We have to initialize it every time. – Amna Feb 28 '20 at 09:29
  • @Amna just remove `using` statement. Just by assigning context to another variable is no help because it is reference type. You just make new pointer. – Arvis Jan 07 '22 at 11:54