7

We have a C# project, which interacts with Active Directory services.

For the context : we use objects from the System.DirectoryServices.Protocols namespace, namely :

  • LdapConnection to connect to the server
  • SearchRequest to scan through entries
  • DirSyncRequestControl to use DirSync capabilities on the SearchRequest

We got stuck for some time on understanding an error which triggered a DirectoryOperationException, before realizing the description of the error what not included in the exception.Message, but was nested further down in the exception object.

We used to have a very simple exception logging when catching such an error :

catch (DirectoryOperationError de) {
    log("ERROR directory error {0} : {1}", de.GetType(), de.Message);
    throw;
}

We now have the following code :

catch (DirectoryOperationException de)
{
    log("ERROR directory error {0} : {1}", de.GetType(), de.Message);

    var resp = de.Response;
    if (resp == null)
    {
        log("          -- no response object linked to exception --");
        throw;
    }

    log("ERROR     directoryresponse error message:'{0}'", resp.ErrorMessage);

    int errorCode;
    var hexCode = resp.ErrorMessage.Substring(0, 8);
    if (!int.TryParse(hexCode, System.Globalization.NumberStyles.HexNumber, null, out errorCode)){
        log("          -- could not figure out error code from '{0}' --", hexCode);
        throw;
    }

    var win32exception = new System.ComponentModel.Win32Exception(errorCode);
    var msg = win32exception.Message;

    log("ERROR     errcode:{0} : {1}", errorCode, msg);

    throw;
}

which ranks pretty high on my "hocus pocus" scale (especially the part where we rely on the string message beginning by an 8 char long hex integer).

Question

Is there a more direct way to access the underlying LDAPError and translate it into a meaningful message using C# ?

15
  • Are you using LdapConnection to talk to AD or DirectoryEntry? Do you get the same error code in de.HResult? Commented Sep 4, 2019 at 14:59
  • 1
    LdapConnection is really created for generic LDAP communication (AD or not), so it has no real optimizations for AD. DirectoryEntry works more closely with AD and will translate a lot of the error messages for you to something meaningful. I'm not suggesting you change that - that might be a lot of work. Commented Sep 4, 2019 at 15:07
  • 1
    It doesn't call GetLastPInvokeError(). You can see here that if you give it an error code, it calls GetPInvokeError(error) (no "Last"). That calls Interop.Kernel32.GetMessage(error), which... Commented Dec 11, 2022 at 23:49
  • 1
    then ends up calling the native Windows FormatMessageW. Commented Dec 11, 2022 at 23:49
  • 1
    @VictorioBerra: I see the "get error message from Win32Exception" as a stable way to translate a numeric code into a message. The concern in my question is more about extracting the code from an error string.
    – LeGEC
    Commented Dec 12, 2022 at 5:02

1 Answer 1

1
+200

Coming back to this question :

I realized that going through a standard LDAP layer to communicate with the server would only get me a standard LDAP Result, e.g a struct with basically one LDAP error code (the resultCode field) and a message string (the diagnosticMessage field).

Perhaps Active Directory could have added controls in its response that would indicate AD specific informations, but it looks like it doesn't.

So all in all, I don't think there can be a much better way to decode that error message : a library would probably just apply a similar treatment on the message string alone, and hope that it is decoding a message coming from an Active Directory -- not a message coming from an OpenLDAP or Novell or whatnot implementation, that happens to start with a valid 8-char hex code.

In our case: since our requests also included controls heavily linked to AD (DirSync controls), the confidence of talking to an Active Directory was basically 100%.


Instead of going through an LDAP connection, I could perhaps have gone through a Win32 API specific function, which could return the Win32 error code as a value, but I haven't had the opportunity to test this when we were faced with this issue.


for reference, a list of possible Win32 error codes is listed here

Not the answer you're looking for? Browse other questions tagged or ask your own question.