Key cannot be null, Parameter name = key (on LdapConnection.Dispose in ReleaseConnection)

Jun 5, 2013 at 6:10 PM
Edited Jun 5, 2013 at 6:28 PM
First I want to say thanks for keeping this updated Madhatter22. I've been using this plugin for over 2 years and it is integral to my application.

So recently I had an error crop up that I can't explain. My 'wrapper-api' that I wrote around yours for my applications hasn't been changed in over a year, my projects I am using it in have not any any VS or .NET framework changes either, yet suddenly I started receiving this error:
System.ArgumentNullException was unhandled
HResult=-2147467261
Message=Key cannot be null.
Parameter name: key
Source=mscorlib
ParamName=key
StackTrace:
at System.Collections.Hashtable.Remove(Object key)
at System.DirectoryServices.Protocols.LdapConnection.Dispose(Boolean disposing)
at System.DirectoryServices.Protocols.LdapConnection.Dispose()
at LinqToLdap.LdapConnectionFactory.ReleaseConnection(LdapConnection connection) in C:\Users\ahatter\Documents\Visual Studio 2010\Projects\linqtoldap\Trunk\LinqToLdap\LdapConnectionFactory.cs:line 137
at LinqToLdap.DirectoryContext.InternalDispose() in C:\Users\ahatter\Documents\Visual Studio 2010\Projects\linqtoldap\Trunk\LinqToLdap\DirectoryContext.cs:line 943
at LinqToLdap.DirectoryContext.Finalize() in C:\Users\ahatter\Documents\Visual Studio 2010\Projects\linqtoldap\Trunk\LinqToLdap\DirectoryContext.cs:line 900
InnerException: 
And if happens every second time the code gets called. So I can run my app, the page loads, if I go to refresh the page, I get this error.

Here is the code I am using to setup the connection:
public static class LdapConnectionConfiguration
    {
        public static string DefaultUserPath { get; set; }
        public static string DefaultGroupPath { get; set; }
        public static LdapConnection DefaultConnection { get; set; }
        public static NetworkCredential DefaultCredentials { get; set; }

        static LdapConnectionConfiguration()
        {
            DefaultUserPath = Constants.LdapConnectionStrings.UserPath;
            DefaultConnection = new LdapConnection(Constants.LdapConnectionStrings.ServerAddress);
            DefaultCredentials = new NetworkCredential("xxxx", "xxxx");
        }

        private static void FinalizeConfig(LdapConfiguration config)
        {
            if (config != null) 
            {
                config.AddMapping(new PersonClassMap());
            }
        }

        public static void ApplyConfiguration()
        {
            LdapConfiguration config = new LdapConfiguration();
            config.UseStaticStorage();
            LdapDirectoryIdentifier directoryIdentifier = (LdapDirectoryIdentifier)DefaultConnection.Directory;
            if(DefaultCredentials == null)
                config.ConfigureFactory(directoryIdentifier.Servers[0]);
            else
                config.ConfigureFactory(directoryIdentifier.Servers[0]).AuthenticateAs(DefaultCredentials);

            FinalizeConfig(config);
        }
    }
And ApplyConfiguration() gets called in my Global.asax file. I am not sure what's wrong since nothing changed, and the connection to AD works, when it doesn't error out, AD is able to be queried from fine.

I store my directory context in the HttpContext:
 public static DirectoryContext Current()
        {
            string objectContextKey = HttpContext.Current.GetHashCode().ToString("x");
            if (HttpContext.Current.Items.Contains(objectContextKey) == false)
            {
                HttpContext.Current.Items.Add(objectContextKey, new DirectoryContext());
            }

            DirectoryContext context = HttpContext.Current.Items[objectContextKey] as DirectoryContext;
            return context;
        }
Again, I haven't touched this code for ages, and it suddenly stopped working. Every pageload after the initial page load, this error comes up. Consistently across all the projects I am using this in.

Any ideas? Thanks.

Edit: I was using 2.5, but I did upgrade to 3.1, still same error.
Jun 5, 2013 at 7:37 PM
Well I found out what's causing this:

http://connect.microsoft.com/VisualStudio/feedback/details/737241/ldapconnection-dispose-throws-argumentnullexception-if-called-twice

Even though the project's didn't change their target framework, the simple fact that I installed 4.5 on my computer made this happen. So LdapConnection.Dispose of can't be called twice. I had a hunch it was somehow related to me storing the context into the HTTP Request, and sure enough this answer explains it:

http://stackoverflow.com/questions/1147993/is-the-httpcontext-current-disposed-even-if-an-exception-is-thrown

objects in HttpRequest.Items are not automatically disposed of, so as defined in the second answer I put this into global.asax:
protected void Application_EndRequest()
        {
            foreach (var item in HttpContext.Current.Items.Values)
            {
                var disposableItem = item as IDisposable;

                if (disposableItem != null)
                {
                    disposableItem.Dispose();
                }
            }
        }
And it took care of the problem!
Coordinator
Jun 29, 2013 at 7:46 PM
That's good to know. Thanks!