How to use LINQ for SharePoint in Anonymous mode
Disclaimer – This has not been extensively tested, so please use the sample below at your own risk!
I am a really big fan of using LINQ to SharePoint. It cuts out all of the nasty CAML and you can do very complex queries with only a few lines of code. The one big let-down was not being able to use LINQ to SharePoint in Anonymous mode… or so I thought!
I actually stumbled across a blog post from Joe Unfiltered on getting LINQ to SharePoint working anonymously, so all the credit goes to him for finding this little gem.
Basically, the problem is with the SPServerDataConnection object. If you crack this baby open with Reflector then you’ll see it relies on SPContext.Current for it’s operations. As the objects it calls are off-limits for anonymous users it forces an authentication prompt!
There is, however, a simple way around this (a technique very similar to one I’ve used before when running with elevated privileges back to the Central Admin SPSite).
You basically do the following:
- Take backup copy of the HttpContext.Current object
- Set HttpContext.Current = null;
- Execute your LINQ to SharePoint query
- Restore HttpContext.Current to it’s original (backup) value
When the SPServerDataConnection object is created, as the SPContext.Current is null it will go ahead and instantiate a new object using the URL you passed through in your DataContext object
Important – Don’t forget to put the HttpContext.Current back again after you have finished your LINQ query. This is VERY important, otherwise things will very quickly start to break!
Sample code is below. Do Enjoy! (and thanks to Joe!)
// store a copy of our current Context’s Web URL
string strWebUrl = SPContext.Current.Web.Url;
bool nullUser = false;
// check if we are running anonymously (i.e. nullUser = true)
nullUser = (SPContext.Current != null && SPContext.Current.Web.CurrentUser == null);
// take a backup copy of the HttpContext.Current object
HttpContext backupCtx = HttpContext.Current;
// if running anonymously, set the current HttpContext to null
HttpContext.Current = null;
// instantiate our data context (using the URL)
MyCustomDataContext thisSite = new MyCustomDataContext (strWebUrl);
// disable tracking to improve read-only performance
eventSite.ObjectTrackingEnabled = false;
// create a list of items from my custom list
- listItems =
// query the list, only selecting items which meet the filter
var currentItems = from listItem in listItems
where listItem.Title != “”
// TODO: process your items
// don’t forget to put your HttpContext back again
HttpContext.Current = backupCtx;
Update – Following this post (and the subsequent discussion on Twitter) there is a lot of questions around performance (creating new SPSite / SPWeb objects for each query) and the validity of nulling the HttpContext.Current in the first place.
My original statement stands .. use this at your own risk, I haven’t fully tested it! If you do your performance benchmarking and you are happy with it then no problem!