CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Brendan Tompkins [MVP]

Blog First. Ask Questions Later.

Windows Server 2003 AD Schema Refresh Issue - Fix

We recently deployed a web application here on our intranet which uses Windows authentication.  During development, on an XP machine, the application worked fine.  When we pushed it into production on a 2003 server machine, we started getting this error:

The directory datatype cannot be converted to/from a native DS datatype

The thing was, the application would work for a while and then stop working.  Well, we tracked this issue down to the following problem, discussed in KB Article 241981:

“With ADSI version 2.0, ADSI forces a schema cache update every time ADSI fails to get the syntax of attribute from the LDAP server, which is represented by the error message above. In ADSI version 2.5, the dynamic schema cache update was removed for performance reasons, and because the forced refresh was thrashing the RootDSE on LDAP version 2.0 servers“

The problem with this KB article is that it discusses how to manually refresh the schema cache, but it's in loosely typed script code. So, after some research, I found a method of the SchemaEntry object that will do the refreshing.  Here's one example of how to to do this:

public string GetProperty(DirectoryEntry de, string PropertyName)
{    
   
de.SchemaEntry.RefreshCache(
new string [] {PropertyName});
   
   
if(de.Properties.Contains(PropertyName)){
      
return de.Properties[PropertyName][0].ToString() ;
    }
    
   
return null;
}

This works, but we found that the web server also had to be “Trusted for Delegation“ by the domain controller machine.  Now, I had our network guy do this, and the combination of the Schema refresh and the trusting did the trick! 

-Brendan



Comments

Brendan Tompkins said:

Darrell, I know, but this server was behind our firewall. I'm not sure what else could have fixed it.
# March 30, 2004 2:27 AM

Brendan Tompkins said:

Darrell, I know, but this server was behind our firewall. I'm not sure what else could have fixed it.
# March 30, 2004 2:27 AM

Darrell said:

I'm not saying you did anything wrong. The permission is there for a reason, but there are security implications to using it. Just an cautionary FYI.
# March 30, 2004 3:36 AM

Zoli said:

Brendan, Darrell, I tried this code and get some error, is there anyone who can solve my problem?

The error details:

1. If I tried this on WinXp wich is my developer serever I got the following error at the "de.SchemaEntry.RefreshCache(new string [] {PropertyName});" line:

Not implemented

2. I tried this on a Win2003 server too. In this case I got another error in the same line wich is "better" then the first one:

Unknown error (0x80005000)
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Runtime.InteropServices.COMException: Unknown error (0x80005000)

Please anybody help me.

Thanks

# May 24, 2004 7:51 PM

Brendan Tompkins said:

Zoli...

If you have trusted for delegation on the Server 2003 machine for current impersonated user, then you are over the first hump.

Second, make sure that your AD contains the property that you are trying to refresh. If you mistype the property, or it's not there, you'll error.

Here are some properties that should be there for AD..

GetProperty(dirEntry, "sAMAccountName");
GetProperty(dirEntry, "givenName");
GetProperty(dirEntry, "sn");
GetProperty(dirEntry, "mail");
GetProperty(dirEntry, "description");
GetProperty(dirEntry, "displayName");
GetProperty(dirEntry, "facsimileTelephoneNumber");
GetProperty(dirEntry, "telephoneNumber");
GetProperty(dirEntry, "title");
GetProperty(dirEntry, "company");
GetProperty(dirEntry, "l");
GetProperty(dirEntry, "department");
# May 25, 2004 2:07 AM

Zoli said:

Brendan...

1. I checked the chekbox Trusted for delegation in the AD and I use Windows authentication and impersonate true. I tried my own account and domain admin too.

2. I wrote a small control, which lists all the properties name for the searched user. I can choose which poperty value will be shown by the number of the property in the list. I use foreach (foreach(string sPropName in osRes.GetDirectoryEntry().Properties.PropertyNames)) to walk through the properties. If the number is equal the selected property number I call the GetProperty whith the sPropName. I think it must be good.

Any new idea?

Thanks
# May 25, 2004 3:43 AM

Brendan Tompkins said:

Well, I'm not sure. I can tell you that your syntax has to be perfect for this to all work. Are you loading the properies when you first get the DirectoryEntery?

One thing that may help you is TokenMon you can get this for free at http://www.sysinternals.com/

Running this on the server will give you an idea if there are permissions problems..
# May 25, 2004 3:46 AM

Zoli said:

Brendan

If You think oADSearchResult.PropertiesToLoad.Add(sPropName);
It is in the code.

I install the TokenMon but I can't see how it can help me. Here is the part of the program, which is working with the AD. Can You check it, please if You see any error.

string NameFilter = tbAdSearchfilter.Text;
string DepartmentFilter="";
string PhoneFilter="";
string sFilterText = "";

DirectoryEntry oADMainEntry = new DirectoryEntry(ConfigurationSettings.AppSettings["ADConnectionString"].ToString());
DirectorySearcher oADSearchResult = new DirectorySearcher(oADMainEntry);oADSearchResult.PropertyNamesOnly = true;
oADSearchResult.Sort = new SortOption("name", SortDirection.Ascending);
sFilterText = "(&(objectCategory=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))";
sFilterText = sFilterText + "(name=" + NameFilter + "*)";
sFilterText = sFilterText + "(department=" + DepartmentFilter + "*)";
sFilterText = sFilterText + "(|(telephoneNumber=" + PhoneFilter + "*)(mobile=" + PhoneFilter + "*))";
sFilterText = sFilterText + ")";
oADSearchResult.Filter = sFilterText;
foreach(SearchResult osRes in oADSearchResult.FindAll())
{
if (cbOnlyUserpCount.Checked)
{
this.Page.Response.Write(osRes.GetDirectoryEntry().Properties["name"].Value + " - " + osRes.GetDirectoryEntry().Properties.Count + "<br>");
}
else
{
int iProp = 0;
foreach(string sPropName in osRes.GetDirectoryEntry().Properties.PropertyNames)
{ this.Page.Response.Write(sPropName); if (cbPropValue.Checked) {
if(tbPropNum.Text.Trim() == "" || int.Parse(tbPropNum.Text) == iProp) {
oADSearchResult.PropertiesToLoad.Add(sPropName);
this.Page.Response.Write(" - " + GetProperty(osRes.GetDirectoryEntry(),sPropName));
}
} this.Page.Response.Write("<br>");
iProp++;
}
}
}


Tanks Zoli


# May 25, 2004 8:58 PM

Brendan Tompkins said:

Zoli,

When you do your foreach, are you failing the first time? If not, there may be a problem with a particluar property.

Also, I'd remove the line PropertyNamesOnly = true; while testing. But, I'm not sure if these could be causing your error.

And, I'd do my GetDirectoryEntry() call once, setting an obj reference, then using that reference.

-B

# May 26, 2004 2:00 AM

Zoli said:

Brendan,

The program always fails at the line
de.SchemaEntry.RefreshCache(new string [] {PropertyName});
This line is called once in the foreach, on that property which I choosed.
If I don't use this line it works fine for exmaple the cn property but fails for the department property. At this time the error occured in the line: de.Properties[PropertyName][0].ToString(), and the error is:
The directory datatype cannot be converted to/from a native DS datatype.
I tried to use the RefreshCache(); without any parameters, but it doesn't help too. Although it not fails in the RefreshCache line, but the error is come in the same line as there wasn't any RefreshCache call.


Changing the PropertyNameOnly is no effect.

Setting up the DirectoryEntry once and using this refence also doesn't indicate any chages.
# May 26, 2004 4:33 AM

Brendan Tompkins said:

Zoli...

Try calling this method within your foreach and run DebugView from http://www.sysinternals.com/ to see what all your properties are.

/// <summary>
/// Write out all of the properties of a given directory entry
/// </summary>
/// <param name="dirEntry" type="System.DirectoryServices.DirectoryEntry">
/// <para>
/// Directory Entry
/// </para>
/// </param>
/// <returns>
/// A void value...
/// </returns>
public static void WriteProperties(DirectoryEntry dirEntry)
{
string[] propNames = new string[dirEntry.Properties.Count];
dirEntry.Properties.PropertyNames.CopyTo(propNames,0);

for (int propertyIndex = 0; propertyIndex < dirEntry.Properties.Count; propertyIndex++)
{
System.Diagnostics.Trace.WriteLine("Name: {0}", propNames[propertyIndex]);
int valueCount = dirEntry.Properties[propNames[propertyIndex]].Count;
for (int valueIndex = 0; valueIndex < valueCount; valueIndex++)
System.Diagnostics.Trace.WriteLine(String.Format(" Value {0}: {1}", valueIndex, dirEntry.Properties[propNames[propertyIndex]][valueIndex]));
}
}
# May 26, 2004 4:43 AM

Zoli said:

Brendan,

At first I would like to very thanks to your help. I don't know what's happened but when I call this method, the progam not fails and starts to work. After that I commented the method call and it is still working. Another sites is start to work after that, althought I didn't modified that code. So if You can expalin me why will it be good, I will be very very happy and probably cleverer too. If You can't expalain the reason, I just congartulate to You because You solved an almost 1 year old problem. Thank You again to your help!

Zoli
# May 26, 2004 9:34 PM

Santosh Kumar said:

Error Type: (0x80072020),
I am not able to acces samaccount name from a windows server2003 active directory from an asp page ( windows script), where i was able to access all the attributes from from windows 2000 server. what would be the proble.
# December 10, 2004 6:54 PM

A Complete Load of Bollocks said:

# November 10, 2005 5:21 AM

Tim Marman said:

KerbTray, part of the Windows Resource Kit, is another useful program for debugging Kerberos/delegation issues. Also, check the security event logs on the AD server to see whether the conenctions are coming in authenticated.

Also, if you are using custom properties / directory entry types, you need to check that the SCHEMA is permissioned appropriately as well or you will see this same "directory datatype could not be..." error.
# June 7, 2006 2:06 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Brendan Tompkins

Brendan has been programming with .NET since the first public beta and is owner and operator of Port Technology Services, a consultancy company providing .NET application development services to the Maritime industry. In July, 2007, he was awarded the Microsoft MVP award for ASP.NET. He's also a proud co-founder of failed .COM startup Intrinsigo, and has had a hand in the failure of numerous other businesses. He currently runs CodeBetter.Com and Devlicio.us, and lives in Norfolk, Virgina with his wife Tiara and son Ian.

View Brendan's profile on LinkedIn

Check out Devlicio.us!

Our Sponsors