Proper way to detect if a ClientObject property is already retrieved/initialized
I would say your question is already contains the correct answer to some extent.
In order to determine whether client object property is loaded or not the following methods are available:
- ClientObject.IsPropertyAvailable method method indicates whether the specified scalar property has been retrieved or set
- ClientObject.IsObjectPropertyInstantiated method indicates whether the specified property of the client object is instantiated
Tests
Test case 1: load scalar property only
ctx.Load(ctx.Web, w => w.Title);
ctx.ExecuteQuery();
//Results:
ctx.Web.IsObjectPropertyInstantiated("Lists") False
ctx.Web.IsPropertyAvailable("Title") True
Test case 2: load composite property only
ctx.Load(ctx.Web, w => w.Lists);
ctx.ExecuteQuery();
//Results:
ctx.Web.IsObjectPropertyInstantiated("Lists") True
ctx.Web.IsPropertyAvailable("Title") False
Test case 3: load both scalar and composite properties
ctx.Load(ctx.Web, w=>w.Lists,w=>w.Title);
ctx.ExecuteQuery();
//Results
ctx.Web.IsObjectPropertyInstantiated("Lists") True
ctx.Web.IsPropertyAvailable("Title") True
How to dynamically determine whether client object property is loaded or not?
Since ClientObject.IsPropertyAvailable and ClientObject.IsObjectPropertyInstantiated methods expect the property name to be specified as a string value and that could lead to typos, I usually prefer the following extension method:
public static class ClientObjectExtensions
{
/// <summary>
/// Determines whether Client Object property is loaded
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="clientObject"></param>
/// <param name="property"></param>
/// <returns></returns>
public static bool IsPropertyAvailableOrInstantiated<T>(this T clientObject, Expression<Func<T, object>> property)
where T : ClientObject
{
var expression = (MemberExpression)property.Body;
var propName = expression.Member.Name;
var isCollection = typeof(ClientObjectCollection).IsAssignableFrom(property.Body.Type);
return isCollection ? clientObject.IsObjectPropertyInstantiated(propName) : clientObject.IsPropertyAvailable(propName);
}
}
Usage
using (var ctx = new ClientContext(webUri))
{
ctx.Load(ctx.Web, w => w.Lists, w => w.Title);
ctx.ExecuteQuery();
if (ctx.Web.IsPropertyAvailableOrInstantiated(w => w.Title))
{
//...
}
if (ctx.Web.IsPropertyAvailableOrInstantiated(w => w.Lists))
{
//...
}
}
The tests provided by Vadim Gremyachev only cover one half of the scenarios - where you use ctx.Load. But when you use ctx.LoadQuery the result changes:
var query = from lst in ctx.Web.Lists where lst.Title == "SomeList" select lst;
var lists = ctx.LoadQuery(query);
ctx.ExecuteQuery();
ctx.Web.IsObjectPropertyInstantiated("Lists") -> True
ctx.Web.Lists.ServerObjectIsNull -> False
ctx.Web.Lists.Count -> CollectionNotInitializedException
So once the LoadQuery has been called on a collection, you can no longer see if the collection is actually available.
Only way in this case is to detect that the exception occurs.