Free SharePoint Redirection WebPart Programming SharePoint WebParts With LINQ to Active Directory Part 2

In the first part of this series, I illustrated the initial building of the primary WebPart class and the workhorse method that taps into Active Directory using LINQ to Active Directory to retrieve the current user’s department. Now, we have to use the returned department string to query down into a helper redirection SharePoint list and use a LINQ query to compare the two strings. We can grab the corresponding value out of the URL column, and they using standard redirection techniques push the user to the destination.

The PushUserToDivisionSite method is responsible for the actual redirection of the user. Firstly, a new SPSite & SPWeb object will be instantiated using the Url property, then a SPList constructed using the List property. To build the Where construct a SPList.Items.Cast<SPListItem>().Where is used performing an Equals on the department of the user and the value of the Title column. This should actually be a String.Compare so that you could bypass any case sensitivity problems, but I am just noticing that now. So you might want to fix that. An Enumerable.FirstOrDefault is used to return the desired SPListItem, and the URL value brought out. This value is then used in a trivial Page.Response.Redirect.

[csharp]

private void PushUserToDivisionSite()
{
using (var site = new SPSite(Url))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists[List];
var results = list.Items.Cast().Where(item => Equals(item[“Title”].ToString(), GetCurrentUserDepartment()));
if (results.Count() > 0)
{
SPListItem hydratedItem = results.FirstOrDefault();
string url = hydratedItem[UrlProperty].ToString();
if (!string.IsNullOrEmpty(url))
{
Page.Response.Redirect(url, true);
}
else
{
HandleException(new Exception(“Redirection Did Not Occur. Please Check The URL Property Of The List Being Used.”));
}
}
}
}
}

[/csharp]

The CreateChildControls method of the WebPart doesn’t do much besides call relevant helper methods. Since the GetCurrentUserDepartment method will either return the department or a constant string value as specified in the global fields, that can simplify be leveraged in a switch. So, either the department is returned, or the constant matches and a new Exception is thrown using the HandleException method which doesn’t do much but emit a literal control.

[csharp]

protected override void CreateChildControls()
{
if (!_error)
{

try
{
base.CreateChildControls();
string department = GetCurrentUserDepartment();
switch (department)
{
case _breakStatement:
HandleException(new Exception(“It Appears Your Active Directory Account Has No Department Set!”));
break;
default:
PushUserToDivisionSite();
break;
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
}

[/csharp]

And that’s it. So going through this again, I think there are two big things that LINQ to Active Directory provides that are crucial to recognize, regardless of whether you like the actual implementation of the concept.

  1. Providing a layer of abstraction over Active Directory functions promotes standardization and ease of use.
  2. Being able to use LINQ querying constructs is extremely helpful when trying to keep code succinct and providing homogenous querying mechanisms.
Share

Free SharePoint Redirection WebPart – Programming SharePoint WebParts With LINQ to Active Directory – Part 1

The real power of LINQ lies in the ambiguity to query collections of all Types, as long as they implement the IQueryable interface. Since Active Directory is essentially a collection of users, one should be able to use a LINQ-esque fashion to manipulate objects out of that particular store as well.

This is where LINQ to AD is awesome! It allows a wrapper to exist around System.DirectoryServices to allow more contemporary, succinct language constructs to be used while developing AD DS integrated tooling. Since I do a lot of security software that exploits AD DS, I wanted to give it a shot!

And it’s pretty impressive. As you can see in the code being explained, there are some quirks, but it’s a pretty cool approach that I believe I am going to use more frequently because I enjoy the layer of abstraction and really, really enjoy being able to use the LINQ code approach.

I have to break this up into two posts because it is exhaustively long. The second post has the download link.

So, for a test project let’s go through building a Redirection WebPart that will satisfy a couple requirements:

  1. Get a reference to the current user
  2. Query into AD DS, find that user, and retrieve the department property
  3. Using the department property, query into a pre-existing SPList, match it, and retrieve a corresponding URL
  4. Redirect the current context to that returned URL

First things first, you have to do download the LINQ to Active Directory project.

Firstly, the appropriate references have to be made, notably to the LINQ to Active Directory project as a referenced project or a compiled assembly. As well, the Active DS Type Library must be referenced so that the IADs interface is exposed. You will see why this is important shortly, but needless to say if not referenced you will get a somewhat cryptic error about an “unspecified error” occurring which is a pain in the ass.

This is what my project structure looks like following:

10-27-2009 1-43-04 PM

As you can see, there are two references out of some pretty orthodox ones being made. The Bds.DirectoryServices.Linq project is referenced, along with the ActiveDs assembly like discussed previously.

The WebPart consists of only two classes. The first one, User, is meant to structure a User object with the properties that should be queried during the AD iterations. For my particular requirement I am only interested in getting the account name and the corresponding department entry. The class and property decorations are provided to specify targets,  DirectoryAttribute for example correlates to the underlying LDAP property to query.

[csharp]

[DirectorySchema(“user”, typeof(IADsUser))]
public class User
{
[DirectoryAttribute(“sAMAccountName”)]
public string AccountName { get; set; }

[DirectoryAttribute(“Department”, DirectoryAttributeType.ActiveDs)]
public string Department { get; set; }
}

[/csharp] 

I am going to throw on some generic properties now into the WebPart class to keep some of the more mutable values dynamic. Just four of them, one a URL string to hyrdate a SPSite object where the SPList exists, a string to represent which SPList to get, a third string to allow the column name to be specified, and a fourth string for the AD DS domain name.

[csharp]

        [Personalizable, WebBrowsable(true),
         WebDescription(“The Url Where The Redirection List Exists”),
         Category(“Global Mode Configuration”),
         WebPartStorage(Storage.Shared),
         DefaultValue(“”),
         WebDisplayName(“URL Of Redirection List Site”)]
        public string Url { get; set; }

        [Personalizable, WebBrowsable(true),
         WebDescription(“Redirection List”),
         Category(“Global Mode Configuration”),
         WebPartStorage(Storage.Shared),
         DefaultValue(“”),
         WebDisplayName(“Redirection List”)]
        public string List { get; set; }

        [Personalizable, WebBrowsable(true),
         WebDescription(“URL List Property”),
         Category(“Global Mode Configuration”),
         WebPartStorage(Storage.Shared),
         DefaultValue(“”),
         WebDisplayName(“Field Name That Contains URL Values”)]
        public string UrlProperty { get; set; }

        [Personalizable, WebBrowsable(true),
         WebDescription(“Active Directory Domain Name To Use”),
         Category(“Global Mode Configuration”),
         WebPartStorage(Storage.Shared),
         DefaultValue(“”),
         WebDisplayName(“AD DS Domain name”)]
        public string DomainName { get; set; }

[/csharp]

Getting the users department from AD using LINQ to Active Directory is a breeze as illustrated in the GetCurrentUserDepartment method below. The _entry global field is a DirectoryEntry object which is intialized OnLoad to the domain string literal specified as a WebPart property (the DomainName auto-property), using some brief string massaging to make it an agreeable DirectoryEntry constructor parameter format-wise.

[csharp]
protected override void OnLoad(EventArgs e)
{
if (!_error)
{
try
{
base.OnLoad(e);
if (!string.IsNullOrEmpty(DomainName))
{
_entry = new DirectoryEntry(string.Format(“LDAP://{0}”, DomainName));
}
else
{
HandleException(new Exception(“Please Set A Domain Name!”));
}
}
catch (Exception ex)
{
HandleException(ex);
}
}
}

[/csharp]

The second SearchScope parameter will specify the tranversal rules for the query, since I want to recur the whole substree I am going to use SearchScope.Subtree.

Following, the current SPContext is going to be used to get a the current SPUser.Login name, which passed into a regular expression to clean it as to match the account name return from Active Directory. An IQueryable<User> collection is built by executing a LINQ Where clause against the previously created DirectorySource object, matching the current SharePoint user to their record in Active Directory. Following, this collection is pushed to a List<User> typed collection using AddRange with the department set off the User.Department property. If no department is returned, it is set to a global string literal that represents a broken (no return) query, used later in conditional statements. Probably should use a String.Compare instead of the equality operator but you get the idea.

[csharp]
private static string GetCurrentUserDepartment()
{
string department = string.Empty;
SPSecurity.RunWithElevatedPrivileges(delegate
{
var usersDs = new DirectorySource(_entry,SearchScope.Subtree);
var cleanUserName = Regex.Replace(SPContext.Current.Web.CurrentUser.LoginName,”.*\\\\(.*)”, “$1”, RegexOptions.None);
IQueryable users = usersDs.Where(usr => usr.AccountName == cleanUserName);
// put in to fix LINQ to AD Bug
var userList = new List();
userList.AddRange(users);
if (userList.Count > 0)
{
User curUser = userList.FirstOrDefault();
department = curUser.Department;
}
else
{
department = _breakStatement;
}
});
return department;
}

[/csharp]

Next Section >> Part II – Building The Remainder Of The WebPart Class

Share

Using TypeMock.NET To Abstract SharePoint With Mocks

On my current project, I am developing some pretty intensive SharePoint WebParts that would otherwise take a ton of time when actually making tangible calls to either the SharePoint object model or database. For this reason, I took the advice of some straight .NET development colleagues with the .NET community and started using mock objects, specifically TypeMock.NET (which, after testing a variety of frameworks, I am finding the most solid while being updated the most frequently).

For those that aren’t familiar with using mock objects with SharePoint, or mocks objects as a whole, you can use a Mock Object as a way to simulate an object instance, incorporating all the behavior of that object, so that you can bypass the expensive need of calling components to otherwise get the calls to work (working together directly within Unit Testing, which will subsequently increasing the overall quality and outcome of your testing). Using mock objects, you can structure a design pattern for your code to run as it would both locally regardless of if you have access to your SharePoint instance since you will be mocking this calls, and then also have a non-mock instance that will eventually become your production deployment package. Your design pattern would in essence keep this synchronized. Furthermore, when using a mock framework, you promote a loosely coupled series of code instead of one that is irrevocably bound to SharePoint (more or less),
The problem that I was running into with SharePoint and mock objects was a relatively straightforward one, for some reason the development team for API support at MSFT decided to seal a bunch of the classes I wanted to mock, and my preferred mock object frameworks don’t support that genius move. To even make the situation worse, a majority of the SharePoint classes are decorated with internal constructors, which limits a bunch of the SharePoint classes so they cannot be instantiated outside of the assembly. Why they are dressed as such, I am not aware.

Nonetheless, I simply wanted to speed up some of my development, and after a bunch of failure, was able to get some rudimentry work done with TypeMock.NET.

Firstly, create a new method that will contain your mock objects. I am going to call mine ExampleSharePointTypeMock().

[csharp]

public void ExampleSharePointTypeMock()
{

}

[/csharp]

Next, place the decorations in front of the method for directives when the method is called. We are going to use the VerifyMocks attribute above the method whose decorator, whose name implies, verifies the mocks at the end of the unit tests that we are going to perform (this can be extended using the Typemock-Isolator to create the such decorations, however it is beyond the scope of this current post) .

[csharp]

[TestMethod,VerifyMocks]
public void ExampleSharePointTypeMock()
{

}

[/csharp]

Now, we actually have to start to create the mock objects that we are going to use. This is really not that tough, and using TypeMock.NET we are able to bypass several of the limitations that are present in several other mock frameworks. These are simply the issues that we talked about in the beginning of this post regarding class sealing and internal constructor use. In order to create some simple SharePoint mock objects, for example a SharePoint list (SPList object) and a SharePoint List Item (SPListItem object) we are going to use the RecorderManager.CreateMockedObject method (you can find out more about this when browsing the Typemock Isolator API Documentation) which will take the type that we wish to mock, outputting the mocked object. So how is it used? Let’s take an example with a simple class to mock, with a whole pile of nothing in it.
[csharp]

public class ClassToBeMocked
{

}

[/csharp]

Then if we wanted to output a mock object from this class, we us the CreateMockedObject method.

[csharp]

[TestMethod,VerifyMocks]

public void MockMethodTest()
{

ClassToBeMocked mockedObject = RecorderManager.CreateMockedObject(typeof(ClassToBeMocked)) as ClassToBeMocked;

}

[/csharp]

Therefore, in order to do the same process with SharePoint, we can just call the orthodox SharePoint objects in a similiar fashion.

[csharp]

[TestMethod,VerifyMocks]
public void ExampleSharePointTypeMock()
{

SPListItem mockedSPItem = RecorderManager.CreateMockedObject(typeof(SPListItem)) as SPListItem;
SPList mockedSPList = RecorderManager.CreateMockedObject(typeof(SPList)) as SPList;

}

[/csharp]

As you can see in the above, we are passing in the two SharePoint types, namely SPList and SPListItem, as parameters in order to create the two mock objects, which after hydration will subsequently be available to us in later code. This is consistent even though the object model has really stupid limitations within it. I am going to do a really simple test, test whether the item name equals the list name.
Afterwards, we are going to use a new RecordExpectations object which as the name implies is a way of managing and setting expectations. We will put this object within an using statement so that when this object is instantiated, we ensure that when we are done with the object, the object’s Dispose method is called at the appropriate time. This, in when executed in MSIL, will get converted by the CLR into try / finally blocks.
[csharp]

public void ExampleSharePointTypeMock()
{
SPListItem mockedSPItem = RecorderManager.CreateMockedObject(typeof(SPListItem)) as SPListItem;
SPList mockedSPList = RecorderManager.CreateMockedObject(typeof(SPList)) as SPList;
using (RecordExpectations recorder = new RecordExpectations())
{

}

}

[/csharp]

We have to set the behavior of this object following which can be a number of properties, I am not going to set it for this example but it helps when restricting unit tests.

Following, we are going to use the ExceptAndReturn method in order to pass in a call, and a secondary argument to conditionally pool the test. In this case, I am going to make sure that the names are well-formed and available, satisfying the conditions I want. You can then use the Assert.AreSame method in order to do further checking to asset whether the correct values are being passed.
[csharp]

public void ExampleSharePointTypeMock()
{

SPListItem mockedSPItem = RecorderManager.CreateMockedObject(typeof(SPListItem)) as SPListItem;
SPList mockedSPList = RecorderManager.CreateMockedObject(typeof(SPList)) as SPList;
string listName = mockedSPList.Name;

string itemName = mockedSPitem[“Title”].ToString();
using (RecordExpectations recorder = new RecordExpectations())
{
recorder.ExpectAndReturn(listName, “test”);
recorder.ExpectAndReturn(itemName, “test”);
}

}

Assert.AreSame(listName, itemName);

[/csharp]

So this example could have been a little more robust and the test is a little redundant I know, however it gets the point of the functionality around I guess.

:)

Share