AccountManagement, PrincipalContext, Principals, And Performance

Often times in trivial AD operations using the *.AccountManagement namespace there is a performance hit in comparison to using ASQ approaches. This has been pretty frustrating to me in the past, as detailed here. In my journeys with these objects though I have determined a better approach. Let’s take the examples from the previous post two methods, GetUser and Get Group. To make these more efficient, we are going to use a combination of PrincipalContext, *Principal, and PrincipalSearcher objects along with a materialized Dictionary object in order to speed things up a bit.

Enough with the filler, let’s look at some code. What we are going to do is create a new PrincipalContext (the static method to hydrate this is discussed in the aforementioned post), then create a new *Principal object consuming the hydrated PrincipalContext in the constructor. The *Principal object will subsequently use the SamAccountName property with a wild card as a search parameter. This *Principal object is then passed into the constructor of a new PrincipalSearcher object so the principal search results can be returned using stuff like FindAll and FindOne. Once the PrincipalSearcher is well formed, we execute a FindAll, ToList to a strongly typed collection with IQueryable support, which allows us to execute a Where clause. The clause leveraged a Regular Expression (ala Regex.IsMatch), and the results are collated in a Dictionary(Of TKey, TValue) according to a specified key selector function. Once the Dictionary is built, a simple if clause is inserted which allows us to find, and return, the object we want! Comparative times of query have shown this cuts down on query time BY 5 TIMES!!!!!!! 

Firstly, the modified GetUser method:

[csharp]

public static UserPrincipal GetUser(string userName)
{
UserPrincipal userPrincipal = null;
SPSecurity.RunWithElevatedPrivileges(() =>
{
PrincipalContext principalContext = GetUserPrincipalContext();
var search = new UserPrincipal(principalContext);
search.SamAccountName = userName + ‘*’;
var ps = new PrincipalSearcher(search);
var pr = ps.FindAll().ToList().Where(a =>
Regex.IsMatch(a.SamAccountName, String.Format(@”{0}\D”, userName))).
ToDictionary(a => a.SamAccountName);
pr.Add(userName, Principal.FindByIdentity(principalContext, IdentityType.SamAccountName, userName));
if (pr.ContainsKey(userName))
{
userPrincipal = (UserPrincipal)pr[userName];
}
});
return userPrincipal;
}

[/csharp]

And the GetGroup method:

[csharp]

public static GroupPrincipal GetGroup(string groupName)
{
GroupPrincipal groupPrincipal = null;
SPSecurity.RunWithElevatedPrivileges(() =>
{
PrincipalContext principalContext = GetGroupPrincipalContext();
var search = new GroupPrincipal(principalContext);
search.SamAccountName = groupName + ‘*’;
var ps = new PrincipalSearcher(search);
var pr = ps.FindAll().ToList().Where(a =>
Regex.IsMatch(a.SamAccountName, String.Format(@”{0}\D”, groupName))).
ToDictionary(a => a.SamAccountName);
pr.Add(groupName, Principal.FindByIdentity(principalContext, IdentityType.SamAccountName, groupName));
if (pr.ContainsKey(groupName))
{
groupPrincipal = (GroupPrincipal) pr[groupName];
}
});
return groupPrincipal;
}

[/csharp]

The first thing you should notice is that these could be placed in a static method of the PrincipalContext as an extension, which would be a whole lot more succint, but I was just happy I got it to work. I’ll leave that up to someone else.

Share

Working Around BehaviorNotImplementedException When Instantiating Stubs

I got this exception in this morning, but thankfully there is a workaround. Do not despair!

Assume the following code. In the Concrete class we have a global level _internalString field and the virtual TestString property with returning the string literal “Pex Is Pissing Adam Off!” (as it was this morning!) in the Concrete base class constructor we are simply backing field settings, nothing amazing. Yeah the virtual member call in the concrete class constructor is bad since it will cause the most derived override to be called, even though the most derived constructor has not been fully run yet (may not be in a suitable state to have that method called). But bah! It’s part of the code and it’s not like that warning isn’t already thrown in nearly every SharePoint artifact.

Anyways, so in the rest of the code there is nothing amazing that is happening, as you can see the class containment hierarchy is using the Concrete base class for the child Superclass derived class, which is just overriding a simple property.

[csharp]
namespace AdamHatingPex
{
public class Concrete
{
private string _internalString;
public virtual string TestString{ get { return “Pex Is Pissing Adam Off!”; } }
public Concrete()
{
_internalString = TestString;
}
}
public class SuperClass : Concrete
{
public override string TestString
{
get { return “But I’ll Get Over It”; }
}
}
}
[/csharp]

Assuming this code, if you stub out the derived class you are going to get a Microsoft.Moles.Framework.Behaviors.BehaviorNotImplementedException error, as you can guess since it’s the only thing in the class it occurs on the overridden property. Quick hint, using CallBase with your call won’t help since base constructors should be run before derived ones (going back to what was discussed previously).
However, it is solvable by changing the behavior. I am not going to get into behaviors yet but you can adjust behavior pre-instantiation of the stub and let it Fall Through or Default Provide A Value. By default the instance will use the BehavedBehaviors.Current property, which will by default throw a BehavedBehaviors.NotImplemented. You can switch this around by setting the InstanceBehavior property on any stub instance. This is pretty easy, demonstrated below:

[csharp]
BehavedBehaviors.Current = BehavedBehaviors.Fallthrough;
var x = new Test.Moles.SSuperClass();
[/csharp]

When you are done with your stuff, you can return to default behavior:

[csharp]
BehavedBehaviors.Current = BehavedBehaviors.NotImplemented;
[/csharp]

If you are interested in this, you should look into the [assembly: PexChooseAsBehavedBehavior] attribute further as well.

Share

Moles On Base Classes

This one took me a little bit to understand. Sometimes the Moles exception handling is so aggressive that it becomes a little tricky to understand exactly what is bubbling up.
Assume MethodX() is a member of base class ConcreteX. Requirements state that you need to have moles for MethodX() in order to support data mocking. It is important to remember for this particular requirement that base member access is achieved by allocating the mole type of ConcreteX and passing the instance in the constructor. This looks like the following:
[csharp]
ConcreteX x = new ConcreteX();
new MObjectContenxt(x).
[/csharp]
Now, if it isn’t done in this fashion MethodX() will not be moled, however you can still mole the entire assembly I suppose. However, doing it in the above fashion avoids using a wrapper in partial classes and a lot of rework based on class hierarchy.

Share