System.NullReferenceException
Object reference not set to an instance of an object.
at Microsoft.ResourceManagement.Client.EnumerationResultEnumerator.Dispose() in C:\FIM2010Dev\Microsoft.ResourceManagement.Samples\Microsoft.ResourceManagement.Client\EnumerationResultEnumerator.cs:line 46
The problem was pretty easy to find, but I thought I'd at least change the code to throw a more helpful exception. The problem happened because I naively tried to use the LINQ methods Count() and First() consecutively:
IEnumerable<RmResource> objects =
client.Enumerate(xpath, selection.ToArray());
if (objects != null && objects.Count() > 0)
{
string result = objects.First()[ATTRIBUTE_DISPLAY_NAME].Value.ToString();
if (!string.IsNullOrEmpty(result))
{
displayName = result;
break;
}
}
However, much like LINQ to SQL behavior, the queries are run on-the-fly as the results are enumerated, and then they're disposed. So, you guessed it, we can't enumerate the results more than once (or at least we should avoid it). You've probably seen this exception from the LINQ to SQL libraries, "The query results cannot be enumerated more than once."
Here's my modified code for the EnumerationResultEnumerator class. I'm throwing a more helpful exception with the message above. I've highlighted my changes:
using System;
using System.Collections.Generic;
using System.Xml.Schema;
using System.Text;
using Microsoft.ResourceManagement.Client.WsEnumeration;
using Microsoft.ResourceManagement.ObjectModel;
namespace Microsoft.ResourceManagement.Client
{
class EnumerationResultEnumerator : IEnumerator<RmResource>, IEnumerable<RmResource>
{
WsEnumerationClient client;
List<RmResource> results;
int resultIndex;
bool endOfSequence;
EnumerationContext context;
String filter;
String[] attributes;
RmResource current;
RmResourceFactory resourceFactory;
bool disposed = false;
internal EnumerationResultEnumerator(WsEnumerationClient client, RmResourceFactory factory, String filter, String[] attributes)
{
results = new List<RmResource>();
this.client = client;
this.filter = filter;
this.resourceFactory = factory;
this.attributes = attributes;
}
#region IEnumerator<RmResource> Members
public RmResource Current
{
get { return current; }
}
#endregion
#region IDisposable Members
public void Dispose()
{
if (!disposed)
{
this.context = null;
this.results.Clear();
this.results = null;
this.disposed = true;
}
}
#endregion
#region IEnumerator Members
object System.Collections.IEnumerator.Current
{
get { return current; }
}
public bool MoveNext()
{
if (disposed)
{
throw new InvalidOperationException("The query results cannot be enumerated more than once.");
}
lock (this.client)
{
if (resultIndex < results.Count)
{
this.current = results[resultIndex++];
return true;
}
else
{
PullResponse response;
if (this.context == null)
{
if (resultIndex > 0)
{
// case: previous pull returned an invalid context
return false;
}
EnumerationRequest request = new EnumerationRequest(filter);
if (attributes != null)
{
request.Selection = new List<string>();
request.Selection.AddRange(this.attributes);
}
response = client.Enumerate(request);
this.endOfSequence = response.EndOfSequence != null;
}
else
{
if (this.endOfSequence == true)
{
// case: previous pull returned an end of sequence flag
this.current = null;
return false;
}
PullRequest request = new PullRequest();
request.EnumerationContext = this.context;
response = client.Pull(request);
}
if (response == null)
return false;
resultIndex = 0;
this.results = resourceFactory.CreateResource(response);
this.context = response.EnumerationContext;
this.endOfSequence = response.IsEndOfSequence;
if (this.results.Count > 0)
{
this.current = results[resultIndex++];
return true;
}
else
{
this.current = null;
return false;
}
}
}
}
public void Reset()
{
if (!disposed)
{
this.results.Clear();
this.context = null;
}
}
#endregion
#region IEnumerable<RmResource> Members
public IEnumerator<RmResource> GetEnumerator()
{
return this;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this;
}
#endregion
}
}
Paolo Tedesco's changes for object count in enumeration responses
As one final note, Paolo has posted code for including the object count in enumeration responses. I haven't tried it yet, but it looks like something I could have used here. Here's the link (note that I'm also posting links to my changes on this thread):
http://social.technet.microsoft.com/Forums/en-US/ilm2/thread/ffc16720-0dfb-4131-b676-9225f15b4f72?prof=required
This comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDelete