Create CSOM ClientContext with re-usability like singleton pattern

1.4k Views Asked by At

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;
        }

    }
3

There are 3 best solutions below

1
On

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.

2
On

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

5
On

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.