Client timeout exception on a simple non-AD query, but S.DS.P works

May 29, 2012 at 9:55 AM

I am trying to write an app which uses LinqToLdap to query an ISODE directory which contains information about our products.  The idea is that the data may migrate to SQL at some stage in the future, so using Linq should mean that the app queries shouldn't need to change much.

I am getting client timeout exceptions when trying to access the response to the LinqToLdap results, but using .Net System.Directory.Services Search works fine.  I am new to LinqToLdap and have tried many variations of query with the same client timeout, so I must be doing something wrong!

The code I am using is:-

        private void TestConnect()
        {
            try
            {
                var config = new LdapConfiguration()
                    .AddMapping(new AutoClassMap<Product>(_productsNamingContext));

                config.ConfigureFactory(MySettings.Hostname)
                    .AuthenticateBy(AuthType.Basic)
                    .AuthenticateAs(new NetworkCredential(MySettings.BindDN, MySettings.BindPassword))
                    .ProtocolVersion(3)
                    .UsePort(MySettings.Port)
                    .ConnectionTimeoutIn(30);

                LdapConnection ldapConnection = config.ConnectionFactory.GetConnection();

                using (var context = new DirectoryContext(ldapConnection, disposeOfConnection: true))
                {
                    context.Log = Console.Out;

                    // --- Using .Net, System.DirectoryServices.Protocol. ---
                    // --- This works and returns 130 results! ---

                    SearchRequest searchRequest = new SearchRequest(_productsNamingContext,
                                                                    "objectClass=bjProduct",
                                                                    SearchScope.OneLevel,
                                                                    null);

                    SearchResponse searchResponse = (SearchResponse)ldapConnection.SendRequest(searchRequest);
                    Console.WriteLine("\r\n.Net Search Response Entries:{0}", searchResponse.Entries.Count);

                    foreach (SearchResultEntry entry in searchResponse.Entries)
                    {
                        Console.WriteLine("S.DS.P, Product {0}:{1}", searchResponse.Entries.IndexOf(entry), entry.DistinguishedName);
                    }

                    // --- Using LINQtoLDAP ---
                    // --- This throws a client timeout exception!

                    Product exampleProduct = new Product();
                    var productsQuery = context.Query<Product>(exampleProduct, SearchScope.OneLevel, _productsNamingContext, "bjProduct");

                    var products = from p in productsQuery
                                   select p;

                    foreach (var product in products) //<<<< Can single step to 'foreach' and 'products', but
                                                        //<<<< step over 'products' causes client timeout exception!
                    {
                        Console.WriteLine("LinqToLdap, Product: {0}", product.CommonName);
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "Directory Connection Error", MessageBoxButtons.OK);
            }
        }

//
// Product.cs
// ----------

using System;
using LinqToLdap.Mapping;

namespace MyApp.LinqToLdap
{
    [DirectorySchema("cn=ProductsRoot, o=my product server, c=GB", ObjectClass = "bjProduct")]
    public class Product
    {
        [DirectoryAttribute("objectClass")]
        public string ObjectClass { get; set; }

        [DirectoryAttribute("dn")]
        public string DistinguishedName { get; set; }

        [DirectoryAttribute("cn")]
        public string CommonName { get; set; }

        [DirectoryAttribute("description")]
        public string Description { get; set; }

        [DirectoryAttribute("bjLastSerialNo")]
        public string bjLastSerialNo { get; set; }

        [DirectoryAttribute("bjVersion")]
        public string bjVersion { get; set; }

        [DirectoryAttribute("bjProductCode")]
        public string bjProductCode { get; set; }

        [DirectoryAttribute("bjPlatform")]
        public string bjPlatform { get; set; }

        [DirectoryAttribute("bjClassifierProduct")]
        public string bjClassifierProduct { get; set; }

        [DirectoryAttribute]
        public DateTime? WhenCreated { get; set; }

        [DirectoryAttribute("LastChanged")]
        public DateTime? LastChanged { get; set; }

    }
}


Console Log
-----------
.Net Search Response Entries:130
S.DS.P, Product 0:cn=Power Widget, cn=ProductsRoot, o=my product server, c=GB
S.DS.P, Product 1:cn=SharePoint Widget, cn=ProductsRoot, o=my product server, c=GB
S.DS.P, Product 2:cn=Another Test Product, cn=ProductsRoot, o=my product server, c=GB
...
... etc
...
S.DS.P, Product 128:cn=Administration UA for MS Windows, cn=ProductsRoot, o=my product server, c=GB
S.DS.P, Product 129:cn=Add to GAL, cn=ProductsRoot, o=my product server, c=GB

Expression: value(LinqToLdap.DirectoryQuery`1[LicenceGenerator.LinqToLdap.Product]).Select(p => p)
Search Request >
Filter: (objectClass=bjProduct)
Attributes: objectClass, dn, cn, description, bjLastSerialNo, bjVersion, bjProductCode, bjPlatform, bjClassifierProduct, WhenCreated, LastChanged
Naming Context: cn=ProductsRoot, o=my product server, c=GB
Scope: OneLevel
Types Only: False
Controls:
Page Size: 500
Page Cookie Length: 0
Page Control Is Critical: True
Page Control OID: 1.2.840.113556.1.4.319


A first chance exception of type 'System.DirectoryServices.Protocols.LdapException' occurred in System.DirectoryServices.Protocols.dll
ErrorCode=85    ServerErrorMessage=null         PartialResults=...      Message=The operation was aborted because the client side timeout limit was exceeded.   Data=...        InnerException={ }      TargetSite={ }  StackTrace=   at System.DirectoryServices.Protocols.LdapConnection.ConstructResponse(Int32 messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut)
   at System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout)
   at LinqToLdap.QueryCommands.StandardQueryCommand.HandleStandardRequest(DirectoryConnection connection, ILinqToLdapLogger log, Int32 maxSize) in C:\Users\ahatter\Documents\Visual Studio 2010\Projects\linqtoldap\Trunk\LinqToLdap\QueryCommands\StandardQueryCommand.cs:line 66
   at LinqToLdap.QueryCommands.StandardQueryCommand.Execute(DirectoryConnection connection, SearchScope scope, Int32 maxPageSize, ILinqToLdapLogger log, String namingContext) in C:\Users\ahatter\Documents\VA first chance exception of type 'System.DirectoryServices.Protocols.LdapException' occurred in LinqToLdap.dll
isual Studio 2010\Projects\linqtoldap\Trunk\LinqToLdap\QueryCommands\StandardQueryCommand.cs:line 45
   at LinqToLdap.DirectoryQueryProvider.Execute(Expression expression) in C:\Users\ahatter\Documents\Visual Studio 2010\Projects\linqtoldap\Trunk\LinqToLdap\DirectoryQueryProvider.cs:line 67      HelpLink=null   Source=System.DirectoryServices.Protocols

Coordinator
May 29, 2012 at 6:05 PM

The paging may be causing the issue.  Considering the size of your results, disabling paging would probably be best.  If you don't have a problem compiling the app yourself, you can download the trunk (disabling paging is a 3.0 feature).  If you don't mind waiting a couple days, I should have 3.0 released by then.

May 30, 2012 at 9:28 AM

Thanks for your prompt reply!  I am happy to compile the code myself, so I'll give that a go.

May 30, 2012 at 10:09 AM

:(
Downloaded and compiled the trunk, and rebuilt my app with config.DisablePaging(), and it still throws a client timeout exception when stepping over the 'products' results collection in the 'foreach'.  Any tips on debugging, or simplifying the search to pin it down, would be welcome.  Meanwhile, I'll keep trying things!

Coordinator
May 31, 2012 at 3:16 AM

You have to change your DirectoryContext constructor in order to pick up on those changes.  Internally it's created it's own configuration since you are not providing one.  Change your constructor to one of the following and let me know if it still fails:

using (var context = new DirectoryContext(ldapConnection, true, config))

OR

using (var context = new DirectoryContext(config))

OR

using (var context = config.CreateContext()))

May 31, 2012 at 8:01 AM

Brilliant! That was it!  It's now returning all results, and no client timeouts.
Thanks for your help!