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# ?
LdapConnection
to talk to AD orDirectoryEntry
? Do you get the same error code inde.HResult
?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.GetLastPInvokeError()
. You can see here that if you give it an error code, it callsGetPInvokeError(error)
(no "Last"). That callsInterop.Kernel32.GetMessage(error)
, which...FormatMessageW
.