2
\$\begingroup\$

I have created a few extension methods to get the direct reports of a UserPrincipal as UserPrincipals themselves. This saves the user of the API quite a bit of typing.

public static IEnumerable<UserPrincipal> GetDirectReportUserPrincipals(
    this UserPrincipal userPrincipal)
{
    var directReportDistinguishedNames =
        userPrincipal.GetDirectReportDistinguishedNames();
    var directReportDistinguishedNamesArray =
        directReportDistinguishedNames as string[] ??
        directReportDistinguishedNames.ToArray();
    if (directReportDistinguishedNamesArray.IsNullOrEmpty())
        return null;
    return userPrincipal.Context.FindUsersByDistinguishedNames(
            directReportDistinguishedNamesArray);
}

public static IEnumerable<string> GetDirectReportDistinguishedNames(
    this UserPrincipal userPrincipal)
{
    return userPrincipal.GetProperty(DirectReports).Cast<string>()
        .Where(
            directReportDistinguishedName =>
                !directReportDistinguishedName.IsNullOrWhiteSpace())
        .ToList();
}

public static PropertyValueCollection GetProperty(
    this Principal principal, string propertyName)
{
    return principal.GetAsDirectoryEntry().Properties[propertyName];
}

public static DirectoryEntry GetAsDirectoryEntry(
    this Principal principal)
{
    return principal.GetUnderlyingObject() as DirectoryEntry;
}

public static UserPrincipal FindUserByDistinguishedName(
    this PrincipalContext principalContext, string distinguishedName)
{
    return UserPrincipal.FindByIdentity(
        principalContext,
        IdentityType.DistinguishedName,
        distinguishedName);
}

public static IEnumerable<UserPrincipal> FindUsersByDistinguishedNames(
    this PrincipalContext principalContext,
    IEnumerable<string> distinguishedNames)
{
    return distinguishedNames.Select(
            principalContext.FindUserByDistinguishedName).ToList();
}

Yes, it does take all of those to do this one task, but the task itself can be called with

userPrincipal.GetDirectReportUserPrincipals();

instead of

  1. Converting user principal to dictionary entry.
  2. Getting direct reports property of dictionary entry.
  3. Casting property to string enumerable.
  4. Using each string (distinguished name) to search for a user principal.

Some of these do feel odd, like they are too Linq-heavy or just unnatural ways of accomplishing the goal. The top method GetDirectReportUserPrincipals has an array cast to avoid "multiple enumeration" as ReSharper says. Is that really necessary?

\$\endgroup\$
4
\$\begingroup\$

Why are you ToListing your collections when you are returning IEnumerable<T>? Unless you have a good reason (rare) then leave them as IEnumerable

GetAsDirectoryEntry seems redundant - and in fact hides the fact that it could be null, whereas somebody calling as directly will know that null is possible. I note when you call it you do not test for null.

In general I prefer the lamba inputs as short names escpecially when the scope is so small, so do

   .Where( dn=>!dn.IsNullOrWhiteSpace())

instead of

   .Where(
        directReportDistinguishedName =>
            !directReportDistinguishedName.IsNullOrWhiteSpace())
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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