Sharepoint Xml feed HttpHandler with Linq

February 7, 2008

Today I’ve been developing an HttpHandler for serving Xml data using a URL-based protocol from a Sharepoint server to the Ajax webparts located in the sites, and I thought it would be a nice experience to share and to start with in my new coding blog !

Currently I am developing a Sharepoint based e-learning portal for a famous university. An ajax webpart had to be developed that enabled teachers to search all the students and get a list filtered by some of the user’s properties (to keep it simple, I’ve limited this example to filter by the user’s name). I decided to use an XmlWebpart from the Sharepoint Ajax Toolkit which would be connected to a filter web part and would get the data from the Xml feed served by an HttpHandler.

In future posts I’ll talk about the ajax webparts, connections and deployment which might be very interesting subjects but for now, I’ll limit to the httpHandler implementation. Following I’ll transcript the code of the ProcessRequest method of the handler comenting all the points that I find interesting and usefull of the implementation.

context.Response.ContentType = "text/xml";
context.Response.Expires = -1;

After setting the response content type to Xml, we open the current SPWeb object to query all the users with the method web.AllUsers. There is no method in Sharepoint object model such as SPUser.IsInRole(rolename) which we all would expect neither there is any way to get a list of the current user’s roles provided the users has Manage Permissions rights in the current site (which is not something likely to happen)What we do have, is a method in SPWeb object called AllRolesForCurrentUser that we can query to check if a user has a particular role. This is what I do in the following code, foreach user in the current web, I open a SPSite object with it’s user token and query if they are in the students role, if so, I store their login name in an array which I finally use to get a SPUserCollection filtered by this array, since there is no way to instantiate a SPUserCollection object and add SPUser objects to it, I thought this approach would be fine. The reason why I want to use the SPUserCollection object is because I want the Xml feed to return the user’s Xml generated by the SPUserCollection.Xml property.

SPWeb web = SPContext.Current.Web;
List userLogins = new List();
foreach (SPUser user in web.AllUsers)
{
using (SPSite site = new SPSite(web.Site.ID, user.UserToken))
{
SPWeb userWeb = site.OpenWeb(web.ID);
SPRoleDefinition studentRole = userWeb.RoleDefinition[SecurityManager.STUDENT_ROLE];
if (userWeb.AllRolesForCurrentUser.Contains(studentRole))
userLogins.Add(user.LoginName);
}
}
SPUserCollection usersInRole = web.AllUsers.GetCollection(userLogins.ToArray());

Now, I still had to filter the SPUserCollection by it’s user name. The filter is passed in the querystring and I decided to use Linq to Xml to do filtering.

string name = string.Empty;
if (!string.IsNullOrEmpty(context.Request["name"]))
name = context.Request["name"];
XDocument usersXml = XDocument.Parse(usersInRole.Xml);
var queryUsers = from u in usersXml.Descendants("User")
where (string.IsNullOrEmpty(name)) (u.Attribute("Name").Value.Contains(name))
select u;

Finally, all what I had to do is return the Xml of the queryUsers objects. I couldn’t find a better way to do it because I didn’t know how to get the Xml from the queryUsers object (keep in mind is my first Linq code!) so following is the choosen method:

context.Response.Write("");
foreach (var u in queryUsers)
context.Response.Write(u.ToString(SaveOptions.None));
context.Response.Write("");

And this is all for this method ! Please leave a comment if you found it useful or wish to suggest any other way to do it ! Although it’s my first post, I promise to keep this blog up to date with many other coding experiences (and I promise I have a lot!)ori