views:

1500

answers:

4

I'm trying to make a web part that greps user comments and stores it in custom list, I wrote this code to add a list to the site once the web part added to the page,

[Guid("c314a0e8-0210-4064-b79e-bfd3594c6083")]
public class CommentWriteSpace : System.Web.UI.WebControls.WebParts.WebPart
{
    SPSite site = null;
    SPWeb web = null;

    public CommentWriteSpace()
    {
        SPSecurity.CodeToRunElevated foo = new SPSecurity.CodeToRunElevated(doit);

        SPSecurity.RunWithElevatedPrivileges(foo);
        SPListCollection listCollection = web.Lists;

        Guid listGuid = listCollection.Add("Comments List", "A list of user comments", SPListTemplateType.GenericList);
        listCollection[listGuid].Fields.Add("User", SPFieldType.User, true);
        listCollection[listGuid].Fields.Add("Comment", SPFieldType.Text, true);
        listCollection[listGuid].OnQuickLaunch = true;
        listCollection[listGuid].Update();
        //this.Page.Request.Url.ToString()
    }

    public void doit()
    {
        site = SPContext.Current.Site;
        web = site.OpenWeb();
    }
}

But the RunWithElevatedPrivileges method throw an exception, I guess it's a permission issue, the exception is the same as one appears when executing site.OpenWeb(); method without elevating privileges.

What could be the problem?

+2  A: 

There is no need for you to run SPContext.Current.Site with elevated privileges. In fact, I think this is why you get the exception. Furthermore, you could also use SPContext.Current.Web instead of site.OpenWeb(). The latter creates a new SPWeb object that you will be responsible of disposing again. SPSite and SPWeb objects from SPContext are automatically disposed when the HTTP request has completed.

Lars Fastrup
"SPSite and SPWeb objects from SPContext are automatically disposed when the HTTP request has completed."Best bit of information on this entire question! Thanks Lars
Dan Revell
A: 

Hmm. Would it maybe be easier to just run the bulk of your code in an anonymous delegate?

SPSecurity.RunWithElevatedPrivileges(delegate()
{
  // Your code here
}

It's probably also better to create an SPList object, rather than accessing the collection repeatedly. Some those collections behave a little strangely - I think it's the SPViewCollection create a new object each time you access it via a guid/index!

All of that askice, I agree with Lars - use SPContext.Current.Web

Andy Burns
-1: you can't use SPContext.Current.Web, it doesn't have elevated privileges.
vitule
+1  A: 

I would suggest avoiding using RunWithElevatedPrivileges when interacting with SharePoint objects (wherever possible, like in your example). You should restrict its use to when you need to access resources that are outside SharePoint (for example a database, file share, etc.)

Here is an excellent article that provides a very elegant approach to getting elevated privileges within a SharePoint context: http://solutionizing.net/2009/01/06/elegant-spsite-elevation/

Daniel McPherson
+4  A: 

You're seeing a number of problems:

  1. SPSite object permissions are determined when they are created, so SPContext.Current.Site will already have the permissions of the current user even if you get the reference within RWEP.
  2. Passing SP objects out of a RWEP block is unsupported and generally dangerous. If you do need to use RWEP, all SPSite and SPWeb objects (and their children) created within that context should be used and disposed in the CodeToRunElevated.
  3. Each call to listCollection[listGuid] will create a new SPList object, which may cause unexpected behavior.

As Dan suggests, RWEP is not the preferred method to do what you're trying to accomplish. Using an extension from the link he references, I would rewrite to look something like this:

[Guid("c314a0e8-0210-4064-b79e-bfd3594c6083")]
public class CommentWriteSpace : System.Web.UI.WebControls.WebParts.WebPart
{
    public CommentWriteSpace()
    {
        SPContext.Current.Site.RunAsSystem(UpdateSite);
        //this.Page.Request.Url.ToString()
    }

    public void UpdateSite(SPSite site)
    {
        SPWeb web = site.RootWeb;

        SPListCollection listCollection = web.Lists;
        Guid listGuid = listCollection.Add("Comments List", "A list of user comments", SPListTemplateType.GenericList);
        SPList list = listCollection[listGuid];

        list.Fields.Add("User", SPFieldType.User, true);
        list.Fields.Add("Comment", SPFieldType.Text, true);
        list.OnQuickLaunch = true;
        list.Update();
    }
}
dahlbyk
Hey mate, nice to see you here!
Daniel McPherson