Directory Programming .NET

Active Directory and ADAM programming support for .NET developers
Welcome to Directory Programming .NET Sign in | Join | Help
in Search

S.DS.AccountManagement GroupPrincipal.GetMembers() != Extended UserPrincipal

Last post 08-26-2008, 9:41 AM by joe. 5 replies.
Sort Posts: Previous Next
  •  08-24-2008, 1:28 PM 4493

    S.DS.AccountManagement GroupPrincipal.GetMembers() != Extended UserPrincipal

    Well sort of.. 

    I have extended base class UserPrincipal with a few extra attributes.  Works great and i'm digging it.  However i have a problem i'm hoping someone can recreate.  Problem is when I start off with a groupPrincipal and invoke the getmembers method, I get a run time error of unable to cast type UserPrincipal to NCSUserPrincipal. 

    My extended class is called NCSUserPrincipal

    PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domain.local.whatever", "DC=domain,dc=local,dc=whatever", ContextOptions.Negotiate, "un", "pw");

    GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "domain users");

    PrincipalSearchResult<Principal> members = group.GetMembers();

    foreach (NCSUserPrincipal u in members) << crashes in this loop unable to cast UserPrincipal to NCSUserPrincipal.

    {

    }

     

    If i start of with a NCSUserPrincipal it works great.  Creating users with extended attributes also works fine.

    NCSUserPrincipal ncs = new NCSUserPrincipal(ctx);

    ncs.otherIpPhone = "3*";

    PrincipalSearcher s = new PrincipalSearcher();

    s.QueryFilter = ncs;

    PrincipalSearchResult<Principal> users = s.FindAll();

    foreach (NCSUserPrincipal u in users)

    {

    //do something here. works great.

    }

     

    Here is the ncsUserPrincipal Class

    [DirectoryRdnPrefix("CN")]

    [DirectoryObjectClass("user")]

    public class NCSUserPrincipal : UserPrincipal

    {

    // Inplement the constructor using the base class constructor.

    public NCSUserPrincipal(PrincipalContext context)

    : base(context)

    {

    }

    // Inplement the constructor with intialization parameters.

    public NCSUserPrincipal(PrincipalContext context,

    string samAccountName,

    string password,

    bool enabled)

    : base(context,

    samAccountName,

    password,

    enabled)

    {

    }

    // Create the otherIpPhone phone property.

    [DirectoryProperty("otherIpPhone")]

    public string otherIpPhone

    {

    get

    {

    object[] result = this.ExtensionGet("otherIpPhone");

    if (result != null)

    {

    return (string)result[0];

    }

    else

    {

    return null;

    }

    }

    set

    {

    this.ExtensionSet("otherIpPhone", value);

    }

    }

    public string office

    {

    get

    {

    object[] result = this.ExtensionGet("physicalDeliveryOfficeName");

    if (result != null)

    {

    return (string)result[0];

    }

    else

    {

    return null;

    }

    }

    set

    {

    this.ExtensionSet("physicalDeliveryOfficeName", value);

    }

    }

    // Implement the overloaded search method FindByIdentity.

    public static new NCSUserPrincipal FindByIdentity(PrincipalContext context,

    string identityValue)

    {

    return (NCSUserPrincipal)FindByIdentityWithType(context,

    typeof(NCSUserPrincipal),

    identityValue);

    }

    //Implement the overloaded search method FindByIdentity.

    public static new NCSUserPrincipal FindByIdentity(PrincipalContext context,

    IdentityType identityType,

    string identityValue)

    {

    return (NCSUserPrincipal)FindByIdentityWithType(context,

    typeof(NCSUserPrincipal),

    identityType,

    identityValue);

    }

    }

  •  08-24-2008, 3:10 PM 4494 in reply to 4493

    Re: S.DS.AccountManagement GroupPrincipal.GetMembers() != Extended UserPrincipal

    So this doesn't look like an error to me.  If you use the built-in GroupPrincipal and try a search, there is no way it would know how to cast to your own derived type.  You are in essence trying to upcast and there could be dependencies there that have no way of being satisfied.

    public Cat: Animal
    {
    }

    abstract Animal
    {
    }

    static Animal[] GetAnimals()
    {
    }


    There is no way for you to cast Animal to Cat here unless you can guarantee that the underlying class is really an Cat coming from GetAnimals (in which case you have the method implemented wrong).  Since in your method the return really is a 'Animal' and not a Cat, the cast should fail.

    It would be different if the method was:

    static Cat[] GetAnimals()
    {
    }


    and you tried:

    foreach (Animal a in GetAnimals)
    {
    }


    this should always work because you are downcasting to a known base class.

    Now, how to fix your problem.  I would say the easiest way is to add a constructor overload to your custom type and do the cast manually yourself like so:

    foreach (UserPrincipal up in members)
    {
        NCSUserPrincipal custom = new NCSUserPrincipal(up); //add this constructor overload
        //... and use here.
    }


    Hope that makes sense.  Short story is that I would expect this behavior and you just need to make a few adjustments to it (it is really about the C# here I think).


    Ryan Dunn
    Extemporaneous Mumblings
    The .NET Developer's Guide to Directory Services Programming
  •  08-25-2008, 9:11 AM 4498 in reply to 4494

    Re: S.DS.AccountManagement GroupPrincipal.GetMembers() != Extended UserPrincipal

    Thanks for your reply. 

    Since i have to create a new object in the for loop i might as well just call the "FindByIdentity" method.

    Thanks for the lesson.  I looked around for more information on up-casting but could not find any examples that are similar to my situation.  If you have any good reads on the topic let me know.

     

  •  08-25-2008, 11:34 AM 4499 in reply to 4498

    Re: S.DS.AccountManagement GroupPrincipal.GetMembers() != Extended UserPrincipal

    What happens if instead of calling foreach you call GetEnumerator<T> directly and pass in the generic type that you want used for return in the enumeration?

    Perhaps this will get the desired behavior?

  •  08-25-2008, 6:52 PM 4500 in reply to 4499

    Re: S.DS.AccountManagement GroupPrincipal.GetMembers() != Extended UserPrincipal

    Joe, I dont see GetEnumerator<T>, only GetEnumerator().  Please explain.

    Thank you.

  •  08-26-2008, 9:41 AM 4503 in reply to 4500

    Re: S.DS.AccountManagement GroupPrincipal.GetMembers() != Extended UserPrincipal

    Sorry, I read the method signature wrong and got confused.  :)

    I don't see a clear, easy way to specify the returned type when using this method either.

View as RSS news feed in XML