internal class StandardQueryCommand : QueryCommand
{
public StandardQueryCommand(IQueryCommandOptions options, IObjectMapping mapping)
: base(options, mapping, true)
{
}
public override object Execute(DirectoryConnection connection, SearchScope scope)
{
SearchRequest.Scope = scope;
var isSorted = Options.SortingOptions != null;
if (isSorted)
{
var sortRequest = new SortRequestControl(Options.SortingOptions.Keys)
{
IsCritical = false
};
SearchRequest.Controls.Add(sortRequest);
}
return Options.PagingOptions == null
? HandleStandardRequest(isSorted, connection)
: HandlePagedRequest(connection);
}
private object HandleStandardRequest(bool isSorted, DirectoryConnection connection)
{
if (isSorted)
{
var pageRequest = new PageResultRequestControl(LdapConfiguration.ServerMaxPageSize);
SearchRequest.Controls.Add(pageRequest);
}
var response = connection.SendRequest(SearchRequest) as SearchResponse;
AssertSuccess(response);
AssertSortSuccess(response.Controls);
return Options.GetEnumerator(response.Entries);
}
private object HandlePagedRequest(DirectoryConnection connection)
{
var pageRequestControl = new PageResultRequestControl(Options.PagingOptions.PageSize)
{
Cookie = Options.PagingOptions.NextPage
};
SearchRequest.Controls.Add(pageRequestControl);
var response = connection.SendRequest(SearchRequest) as SearchResponse;
AssertSuccess(response);
AssertSortSuccess(response.Controls);
var pageResponseControl = GetControl<PageResultResponseControl>(response.Controls);
var parameters = new[]
{
Options.PagingOptions.PageSize,
pageResponseControl.Cookie,
Options.GetEnumerator(response.Entries)
};
return Activator.CreateInstance(
typeof(LdapPage<>).MakeGenericType(Options.GetEnumeratorReturnType()),
parameters);
}
private static void AssertSortSuccess(IEnumerable<DirectoryControl> controls)
{
var control = GetControl<SortResponseControl>(controls);
if (control != null && control.Result != ResultCode.Success)
{
throw new LdapException(
string.Format("Sort request returned {0}", control.Result));
}
}
}
Sort requests require paging or else you'll get a size limit exceeded if you have too many results. I thought this was all I needed to worry about, but when I tried to filter 50K entries I found another gem. The response of the sort request was "UnwillingToPerform". I felt like my laptop just told me to take a hike. I Googled and only turned up that something was wrong with my sort. I looked at my query and it hit me:
var orderBy = context.Query<User>()
.OrderByDescending(u => u.LastName)
.Select(u => new User {CommonName = u.CommonName, FirstName = u.FirstName, LastName = u.LastName})
.ToPage(50);
Basically this is the same error as size limit exceeded. Even with a page request, the filter is too broad to effectively perform a server side sort, so it fails. I applied a filter and everything worked.
Sorting is not an efficient operation for the server which is why it has a size limit. Unless you're working on a horribly constrained client, I recommend doing your sorting there.