1

Consider the following pieces of code from an Active Directory service I have. In the Rename() method it always throws an ObjectDisposedException, "Cannot access a disposed object. Object name: 'DirectoryEntry'."

This used to work fine, but I also have an Add() method and the two were 95% identical code. So, I opted for the SetIdentity() method to which I would pass the principal and the properties dictionary and go from there. The Add() method works, but that's because there's no underlying object to manipulate yet. The Rename() method fails because there is one.

I know that if I put the code from SetIdentity() back into Rename() it will work just fine, but I don't want to do that.

I've tried wrapping the using clause in Rename() in a try/catch block, but it didn't do anything. I've tried passing the principal and dictionary by ref, but that also didn't help. I've tried checking if the DirectoryEntry is null and it didn't help.

So, I'm guessing it can't be the code inside the using clause that's failing. What else should I look for?

When debugging with Visual Studio I can hover over the object and it's there and complete with properties and values, so I don't know where I'm supposed be looking...

public override void Rename(
    UserPrincipal principal,
    IDictionary<string, object> properties) {
    if (principal != null) {
        this.SetIdentity(ref principal, ref properties);

        using (DirectoryEntry entry = (principal.GetUnderlyingObject() as DirectoryEntry)) {
            entry.Rename(newName: String.Format("CN={0}", principal.DisplayName));
            entry.CommitChanges();
        };

        principal.Save(); // this is where ASP.NET runtime points to when failed
    };
} // this is where Visual Studio points to when debugging

internal void SetIdentity(
    ref UserPrincipal principal,
    ref IDictionary<string, object> properties) {
    object obj = null;
    string displayName = string.Empty;
    string givenName = string.Empty;
    string middleName = string.Empty;
    string samAccountName = string.Empty;
    string surname = string.Empty;

    if (properties.TryGetValue("GivenName", out obj)) {
        givenName = (string)properties["GivenName"];
    };

    if (properties.TryGetValue("MiddleName", out obj)) {
        middleName = (string)properties["MiddleName"];
    };

    if (properties.TryGetValue("Surname", out obj)) {
        surname = (string)properties["Surname"];
    };

    if (properties.TryGetValue("SamAccountName", out obj)) {
        samAccountName = (string)properties["SamAccountName"];
    };

    if (String.IsNullOrEmpty(middleName)) {
        displayName = String.Format("{0} {1}", givenName, surname);

        if (String.IsNullOrEmpty(samAccountName)) {
            samAccountName = String.Format("{0}{1}", givenName[0], surname);
        };
    } else {
        displayName = String.Format("{0} {1}. {2}", givenName, middleName[0], surname);

        if (String.IsNullOrEmpty(samAccountName)) {
            samAccountName = String.Format("{0}{1}{2}", givenName[0], middleName[0], surname);
        };
    };

    samAccountName = samAccountName.ToLower();

    principal.DisplayName = displayName;
    principal.GivenName = givenName;
    principal.MiddleName = middleName;
    principal.SamAccountName = samAccountName;
    principal.Surname = surname;
    principal.UserPrincipalName = String.Format("{0}@dryforce.com", samAccountName);
}
4

1 回答 1

6
   using (DirectoryEntry entry = (principal.GetUnderlyingObject() as DirectoryEntry))

为 .NET 设计者购买一支雪茄,以获得良好的方法命名。您正在使用 using 语句处理“基础对象”。你猛地一拉地垫,让课堂正常运转的东西已经不复存在了。这是一只死鹦鹉。一个等价的方法是处理 StreamReader.BaseStream。在你这样做之后尝试从中读取将会去 Kaboom,无法从已处理的底层对象中读取。

处理它不是你的工作,你的代码没有创建它。通过省略using关键字来解决问题。

于 2012-08-31T23:06:57.837 回答