Linq to SharePoint. Part 3
Part 1. First()/FirstOrDefault(), T-SQL IN, Path
Part 2. Count(), Take(), Skip(), JOIN, ObjectTracking
Part 3. Anonymous access, Resolve list by URL
Part 4. Dynamic LINQ, Convert SPListItem to data context object
Part 5. Choice and MultiChoice fields
Resolve list by URL
There is GetList
Another pair of shoes is a list' URL: user can's change it and localization doesn't matter. But there is no method that returns a list by its URL in the SharePoint API. To resolve this trouble you can use SPWeb.GetFolder(string strUrl) method. The result of it is SPFolder object that contains ParentListId property. Following method represents this trick:
/// <summary>
/// Resolve list by URL
/// </summary>
private EntityList<T> GetListByUrl<T>(string listUrl)
{
string listTitle;
using(var site = new SPSite(Web))
{
using(var web = site.OpenWeb())
{
var folder = web.GetFolder(listUrl);
var list = web.Lists[folder.ParentListId];
listTitle = list.Title;
}
}
return GetList<T>(listTitle);
}
The method is cool, but also has a limit: URL must be site relative. Like these:
"/Lists/Departments",
"/Lists/Departments/AllItems.aspx",
"/DocLib/Forms/AllItems.aspx"
This method works some slower 'cause of initialisation of these object: SPSite, SPWeb, SPFolder and SPList.
Anonymous access
There is another trouble with user Linq to SharePoint: it can't work in anonymous access mode. The reason is this: SPContext.Current.Web.CurrentUser property in anonymous access mode is NULL. And SharePoint throws up an exception. It's enough to check out the constructor of SPServerDataConnection class (it used for retrieving data from SharePoint lists) to understand how to resolve it:
public SPServerDataConnection(string url)
{
if (SPContext.Current != null)
{
this.defaultSite = SPContext.Current.Site;
this.defaultWeb = (SPContext.Current.Web.Url == url)
? SPContext.Current.Web
: this.defaultSite.OpenWeb(new Uri(url).PathAndQuery);
}
else
{
this.defaultSite = new SPSite(url);
this.defaultWeb = this.defaultSite.OpenWeb(new Uri(url).PathAndQuery);
}
if (!this.defaultWeb.Exists)
{
throw new ArgumentException(
Resources.GetString("CannotFindWeb", new object[] { url }));
}
this.defaultWebUrl = this.defaultWeb.ServerRelativeUrl;
this.openedWebs = new Dictionary<string, SPWeb>();
this.openedWebs.Add(this.defaultWebUrl, this.defaultWeb);
}
If the current context is null it re-created using the current URL. This is the first point. The second one is that it's necessary for someone to account to impersonate it. We can use SPSecurity.RunWithElevatedPrivileges static method, which executes delegate transferred to it with full control rights. Following code executtes method with full control right if the current user is null:
public static void RunAsAdmin(SPSecurity.CodeToRunElevated secureCode)
{
// Anonymous access flag
var isAnonymous = SPContext.Current.Web.CurrentUser == null;
// Is it necessary to reset current context
var nullUserFlag = (SPContext.Current != null && isAnonymous);
if (nullUserFlag)
{
// Save current context
var backupCtx = HttpContext.Current;
// Reset current context
HttpContext.Current = null;
// Execute code
SPSecurity.RunWithElevatedPrivileges(secureCode);
// Restore the context
HttpContext.Current = backupCtx;
}
else
{
// Execute as is
SPSecurity.RunWithElevatedPrivileges(secureCode);
}
}
This static method may be used inside a custom data context.
That's something like this.