24

In SharePoint 2013 CSOM is it better to pass a Context object around, or a Url to open a context?

Which would be the best example: (Please consider there may be a lot of methods preforming tasks)

1) Pass Context, open Web

EnableSomethingOnWeb(ClientContext ctx, bool enable){
   ctx.Load(ctx.Web);
   // enable something
   ctx.ExecuteQuery();
}

var ctx = new ClientContext("http://myweb");
EnableSomethingOnWeb(ctx, true);

2) Pass Url, open ClientContext, Open web

EnableSomethingOnWeb(string Url, bool enable){
   var ctx = new ClientContext(Url);
   ctx.Load(ctx.Web);
   // enable something
   ctx.ExecuteQuery();
}

EnableSomethingOnWeb(webUrl, true);

3) Pass Web, Execute ClientContext

EnableSomethingOnWeb(Web web, bool enable){

   // enable something
   web.Context.ExecuteQuery();
}

var ctx = new ClientContext("http://myweb");
ctx.Load(ctx.Web);

EnableSomethingOnWeb(ctx.Web, true);
*keep in mind following calls may continue pass this web object around.
Elliot Wood
  • 472
  • 1
  • 4
  • 10

2 Answers2

15

Do:

  • Pass around ClientContext.
  • Call .ExecuteQuery() as few times as possible, bundle/batch up with .Load().
    • Once is usually enough, only in a very few cases do you need more.

Do not:

  • Do not pass around Web.
    • You need to reference other members from ClientContext, such as Site.
  • Do not pass around an URL (either as String or Uri).
    • Initialization method of ClientContext can alternate, e.g., provider hosted apps use this: SharePointContextProvider.Current.GetSharePointContext(HttpContext).CreateUserC‌​lientContextForSPHost().

Also:
I usually make "Repository" classes, which work on ClientContext without actually calling .ExecuteQuery(), so I bundle up (batch) .Load commands and fire them on the "outside", then come back to the Repository.

public class ListAndViewRepository
{
    private readonly ListCollection _lists;
    public List<List> Lists { get; set; }
    public List<View> Views { get; set; }

    public ListAndViewRepository(ClientContext clientContext)
    {
        _lists = clientContext.Web.Lists;
        clientContext.Load(_lists,
            collection =>
                collection.Include(l => l.Id, l => l.Title,
                    l => l.Views.Include(v => v.Id, v => v.Title, v => v.ViewFields, v => v.ViewQuery)));
    }

    public void Execute()
    {
        Lists = _lists.ToList();
        Views = Lists.SelectMany(list => list.Views.ToList()).ToList();
    }
}

Used something like this:

var listAndViewRepository = new ListAndViewRepository(clientContext);
// ... do a lot of other "repositories"
clientContext.ExecuteQuery();
// ... call "Execute" on other "repositories"
listAndViewRepository .Execute();
var lists = listAndViewRepository.Lists;
var views = listAndViewRepository.Views; 
eirikb
  • 7,405
  • 5
  • 35
  • 67
  • So to clarify, constructing class libraries should use "ClientContext" because of multiple ways to init the object may cause inconsistencies? – Elliot Wood Apr 14 '14 at 05:51
  • 1
    @ElliotWood: Yes, they should not initialize the object. In provider hosted apps you do something like SharePointContextProvider.Current.GetSharePointContext(HttpContext).CreateUserClientContextForSPHost() instead of just new ClientContext. – eirikb Apr 14 '14 at 05:53
  • Could you please help me with this question : https://stackoverflow.com/questions/53893774/how-to-manage-client-context-object-in-seperate-class-library – I Love Stackoverflow Dec 22 '18 at 07:22
5

Objects like Web, ClientContext are passed by reference, that is they are not copied. So there is no need to worry about performance. However, as mentioned by @eirikb, pasing ClientContext between methods make more sense as you can then load whatever objects you want from it inside the method.

Nadeem Yousuf-AIS
  • 18,707
  • 4
  • 28
  • 59
  • Note that when you initializing a new instance of ClientContext it will validate the URL, so at least 10 nanoseconds to save there. Although when initializing in a provider hosted app the overhead is much much larger – eirikb Apr 14 '14 at 05:44
  • @eirikb, so it is good to initialize ClientContext once and then pass between methods rather than passing url and initializing inside the method. – Nadeem Yousuf-AIS Apr 14 '14 at 05:54
  • @Nadeem So by ref would imply you could get the context and call other things by going: var ctx = web.Context; ctx.Load(...)?? – Elliot Wood Apr 14 '14 at 05:56
  • @ElliotWood, That is right. However, if ClientContext is passed instead of Web then there is no need to do var ctx = web.Context – Nadeem Yousuf-AIS Apr 14 '14 at 06:05