SPMetal with Anonymous Access


So, I recently ran into a problem with using SPMetal with anonymous access. When Anonymous users access a web part that runs LINQ queries, they’ll get prompted for credentials in SharePoint 2010. The problem is actually related to the way the LINQ code works. It uses the default SPContext.Current to get the site objects. This becomes a problem when you need to run a piece of code with elevated permissions because without rebuilding the SPContext.Current, you’re still using the default permissions. With the default permissions, as an anonymous user, you will not have enough access to make calls using LINQ and as a result, you’ll be prompted to log in.

This blog had an okay solution:

Use the HttpContext object to force all SP objects to be created again. When this happens within the RunWithElevatedPrivileges method, the SPContext is recreated with this higher level of priveleges.

This code has its problems though.

To do this he used the logic below:

  1. Check if the situation requires action: Is the user anonymous?
  2. Backup the current HttpContext
  3. Set the current HttpContext to null – thus forcing the creation of new SP* objects
  4. Use The RunWithElevatedPrivileges method to execute code specified by the caller. Note that I reuse the SPSecurity.CodeToRunElevated delegate to mimic the RunWithElevatedPrivileges method.
  5. Set the current HttpContext to the backed up object
After reading a little deeper into his article, I realized that he was mistaken about the SPContext.Current. Its not Read Only, its just static. This means you can set it to a value, you just can’t instantiate a new one.
After looking deeper into his solution, I realized something else. The SPContext.Current has a ResetItem() method that forces it to retrieve new SP objects within the Current SPContext, which is exactly what we need.
So, instead of going through the trouble, and risk, of messing with the HTTPContext you can simple call the ResetItem() method before and after you run your LINQ.
It will look something like this:

try

{

// Running my Code with elevated Permissions

SPSecurity.RunWithElevatedPrivileges(delegate()

{

using (SPSite CurrentSite = new SPSite(CurrentContextURL)) // Use the URL of the current Context

{

using (SPWeb CurrentWeb = CurrentSite.OpenWeb())

{

SPContext.Current.ResetItem(); // Resetting Context

// Running my Code

using (LINQDataContext dc = new LINQDataContext(CurrentWeb.Url))

{

// Your Code Goes Here

}

}

}

});

}

catch (Exception ex)

{

ErrorCaught = ex;

}

finally

{

// resetting the SPContext

if (SPContext.Current != null)

SPContext.Current.ResetItem();  // Resetting Context

}

Hope this helps. As always, if you find any mistakes are feel this can be improved, let me know!
Advertisements
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: