Category: Sharepoint 2007

Running SharePoint Code with Elevated Privileges – A Real Example

By , August 31, 2009

In case you didn’t know, there is a construct built into SharePoint that allows developers to create code that runs as the System Account instead of the logged in user, essentially giving that user Administrator Level Permissions in a confined space. I will go over the code required to do this below, but essentially you have a block of code within your larger project that needs the logged in user to have certain permissions that they may not have, and this small block of code will then be run as the System Account, giving it the permissions needed for the task at hand.

Well, at first thought everyone I have explained this to has the same questions and concerns, “Why would you ever want to do that?” or “That is a huge security risk!”.
I could never come up with a very good example to explain it and my attempts to reassure customers that the security risk is very minimal as the user will only have permission to do exactly what the developer lets them sometimes was not well understood.

Well I finally had a project that required me to do this, so I figured I would share it to give a fairly simple real world example.

Project Objective: Create an extranet to serve as a customer support site where users can log Service Requests, manage their account, order new products, etc. via the web or by phone.

This is fairly simple and something I have done several times for different customers, but this project had one difference. Service / Support Requests could be made by phone, where all of my other projects were strictly web oriented. Does anyone see the problem this raises yet? Well I eventually incorporated the Cisco phone system into the site to generate Service Requests, but that is not what I am talking about. With any system like this, it is vital that customers only have access to their own Service Requests (as in they cant view other user’s requests).

Typically, when using a SharePoint list one can turn on the settings in the Advanced Settings section of a List (seen below) so that users can only view and edit their own List Items. This is very handy and works very well when users are always the creator of their own items, but in this case when someone calls in, someone else will be creating the service request for them… see the problem? Well, I thought about trying to change the Created By field to the user that called in, but decided it would be a neat place to use the elevated permissions approach.

Advanced List Settings

The Solution: So, this is the summary of what I did. I didn’t give any customers permissions to the Service Request List at all from within SharePoint. All access that customers had to that List was done through custom forms and web parts that made use of the elevated permission construct. This ended up being 3 forms and 3 web parts that used Elevated Permissions. Customers would use one form to create a Service Request, another to view it, another to edit it and then three web parts to display the contents of the list on various pages.

I added a custom text field to the list called Customer ID which would store each customer’s unique ID, detailing who each Service Request belonged to. The custom forms that users would use would populate this field upon creation by looking to see who the current user was, and looking up their ID in another List. Likewise when a member of the support staff was creating a service request received over the phone, they would fill in the Customer’s ID before creating it (The phone system was later used to automate this). This way, we are not relying on the Created Field to limit what each user is allowed to see.

Below I will go through the basics of how Elevated Permissions work and then show in more detail how I used it in my solution. Then in the next few days I hope to stick out a web part that incorporates it as well.

This is the basic code snippet you need to run with elevated permissions:

private void yourFunction()
{
      // Non-Elevated Permission Code Goes Here

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            // Elevated Permission Code Goes Here
      });      

      // Non-Elevated Permission Code Goes Here
}

Pretty much everything you find online about this has code that is poorly explained, so hopefully I can do a decent job and make it easy. The code above is simple enough right? Well here is one place people routinely run into problems. If you are using an instance of SPWeb or SPSite before your Elevated Permission Code block, you won’t be able to use it. You need to get a new instance of the SPWeb or SPSite object to use once you enter the elevated block. Below is the code that I use to do this.

private void yourFunction()
{
      SPSite site = SPContext.Current.Site;
      SPWeb web = SPContext.Current.Web;

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            using (SPSite ElevatedSite = new SPSite(site.ID))
            {
                  using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb(web.ID))
                  {
                        // Code Using the SPWeb Object Goes Here
                  }
            }
       });
}

I am pretty sure that little tidbit cost me about a day the first time I tried to play with Elevated Permissions, so hopefully that will help some of you out. After that, it is really simple as you just put your code in the middle of it just like you would if you weren’t using the elevated permissions.

As further example, in my NewSR.aspx form that users go to when creating a new Service Request, I use a runWithElevatedPrivileges block in two functions. The first is a private function I call within the OnPreLoad() function called LoadData(). Inside this function I am populating drop down menus from data in a SharePoint list for the Priority of the service request and the products that are affected.

The second function with a runWithElevatedPrivileges block is my onSubmit() function that is called when a user clicks the submit button.

New SR Form

So it is actually pretty simple. The only other thing I am going to demonstrate is how I made the view and Edit Forms Secure. As you probably know, every List Item has an integer ID (.ID) and a unique guid ID (.UniqueID). Well, the custom forms I made for view and edit look in the querystring for a guid which it then uses to look up the Service Request. (If you can guess the guid of another service request, well you broke my security but it seems quite unlikely) There isn’t anything fancy about accessing the querystring to get the guid and look up the Service Request, but I thought it would be handy to store a link to the item within the item itself as an additional field. This makes it easy to email the user a link to view their service request among other things.

So I created a text field called Link and populated it as shown below.

private void yourFunction()
{
      SPSite site = SPContext.Current.Site;
      SPWeb web = SPContext.Current.Web;

      SPSecurity.RunWithElevatedPrivileges(delegate()
      {
            using (SPSite ElevatedSite = new SPSite(site.ID))
            {
                  using (SPWeb ElevatedWeb = ElevatedSite.OpenWeb(web.ID))
                  {
                        srList = ElevatedWeb.Lists["Service Requests"];
                        SPListItem newItem = srList.Items.Add();
                       
                        // Do stuff to create the list item
 
                        ElevatedWeb.AllowUnsafeUpdates = true;
                        newItem.Update();
                        Guid temp = newItem.UniqueId;
                        newItem["Link"] = "<DIV><a href=\"https://YourSite.com/_layouts/custom/ViewSR.aspx?ID=" + temp.ToString("d") + "\">View SR</a></DIV>";
                        newItem.Update();
                        ElevatedWeb.AllowUnsafeUpdates = false;
                  }
            }
       });
}

The tricky part here is having to call item.update() twice. You have to call it twice because the first time you call it is when the list item is actually created. Before then, it does not have a Unique ID to reference. So once it is created, you can grab the Unique ID, and populate the Link field with a HTML formatted URL that references the item and can be easily inserted into a HTML based email or a page that has a content editor web part CEWP with the JavaScript in it found here. You then call update the second time to save your link field.

Support Screen with Link

The use of the link field and the JavaScript found above allows me to render links in a web part as shown above.

Well, hopefully this will be useful to someone – I think it would have saved me a day or so once upon a time when I first tried to do this.

Getting Started: The Basics of Web Part Development

By , August 11, 2009

Introduction

I taught a week long SharePoint boot camp about a month ago for Microsoft Enterprise Customers that pretty much covered everything SharePoint.  The first day dealt with Planning and Governance, days 2 and 3 went over Administration and Point&Click design, and Days 4 and 5 involved custom development.

Over the next month or so I plan to put up quite a few of the examples I used during the class, but today I want to go over how to get started with Web Parts and then build onto the topic in later postings.  It is one of my favorite things to code in SharePoint and a good foundation will definitely make your life easier in the long run.  You have to have some understanding of the Page Life Cycle to follow what is happening when, and hopefully after reading this you will be better equipped to go roll your own.

I will cover this topic  in five small sections:

  1. The Page Lice Cycle
  2. The Web Part Life Cycle
  3. Tools to help make Web Parts
  4. The Hello World Web Part
  5. Adding functionality to your Web Part

Before I get started, I just want to point out is that Web Parts are not a SharePoint construct – they are simply an ASP web control.  ASP web parts can be used in SharePoint and Web parts you make for your SharePoint site may be used in an ASP based web page (If you do everything correctly).  We however will focus on SharePoint.

The Page Life Cycle

When a request is received for an ASP page, the .NET framework runs the page through a series of steps to initialize objects, analyze the request, view any state and post back information, handle any raised events and finally render the output.  A solid understanding of the page life cycle will let you better understand what and when everything is happening.  More importantly perhaps, it will let you understand where you need to put your code that it fits in correctly.  Below are the 6 stages of the Page Life Cycle.  Note that they are not official stages, but are being grouped logically here.

  1. Page Request
    1. Determines if the requested page is cached
    2. There are no methods to override at this stage
  2. Start up
    1. The Request and Response properties are set
    2. Determines if there is a new request or post back
    3. There are no methods to override at this stage
  3. Initialization
    1. Themes and Master pages are applied
    2. Controls are created in the Web Part’s OnInit() Method
    3. Client side scripts and connection strings are registered
    4. The OnInit() method for the page is invoked after each child control’s OnInit()
  4. Loading
    1. Properties that utilize the post back or view state are set
    2. Initial or default values are set in the OnLoad() Function
    3. The Page’s OnLoad() is invoked before each child control’s OnLoad()
  5. Rendering – 3 Sub Phases
    1. Pre-Render
      1. EnsureChildControls() and CreateChildControls() are called
        1. Note: All Controls should be added through CreateChildControls()
      2. OnPreRender() is called which is the last chance to edit the page
        1. OnPreRender() for the page is called which recursively calls each control’s
    2. Save State
      1. The View and Control States are created and saved
    3. Render
      1. All controls process their Render() method and generate HTML
  6. Unloading
    1. This is the final stage where open files and database connections are closed
    2. There are no methods to override at this stage

The Web Part Life Cycle

It is kind of hard to separate the Web Part life cycle from the Page’s as the Web Part runs within the context of the Page, but it helped me understand it when I tried to separate it out.  You could also look at this little part as a summary of what is really important from the above section.

  1. Initialization Stage

    1. Web Part’s OnInit() is called BEFORE the Page’s OnInit()
    2. The SPWebPartManager loads and applies any personalization settings
  2. Loading Stage
    1. Web Part’s OnLoad() is called AFTER the Page’s OnLoad()
  3. Render Stage
    1. CreateChildControls() is called – Add your controls here
    2. OnPreRender() is called AFTER the page’s OnPreRender()
    3. RenderContents() is called

Tools for Web Part Development

So, now that we have a basic outline of when events occur in the life cycle of a web part, we need to start developing.  There are a couple of tools that will definitely make your life easier that I highly recommend.  The first one is Visual Studio Extensions for SharePoint which is a plug in for Visual Studio that has a web part template.  The newest version (1.3) made some very good improvements and even lets you deploy a web part to the local bin folder instead of the GAC.  This is the tool I will be using later in this segment and what I generally use for all of my web part projects.

The second tool you should look at is the SharePoint Dispose Checker Tool which scans your code for SharePoint Memory leaks related to improper Dispose calls.  Run this before ever putting your SharePoint code into production – memory leaks are bad.

The Hello World Web Part

Note: You can download the project I go through below Here if you don’t want to follow along.

So, now that you have installed the Visual Studio Extensions for SharePoint, create a new Project and select SharePoint –> Web Part as the project template.  This will give you a blank web part that has a webpart.xml file that defines properties on the web part, a .webpart file that further defines the web part and a c# file with the code for the web part.

The first thing we want to do is rename the webpart.xml file to the name you want your web part to have.  It will ask you if you want it to change the name throughout the project, select yes.  Next, open up the Webpart.xml file and modify the <file> tag as shown below.  By adding the property tag to it, it allows us to group our web parts in the “Add New Web Part” dialog box sharepoint users will see when adding a web part to their page.  An Image of how this will work is also shown below, showing one of my test servers and several web parts I have made listed under my custom group header.

<File Path=“HelloWorld.webpart" Url=“HelloWorld.webpart" Type="GhostableInLibrary">
    <Property Name="Group" Value="Steve's Custom Web parts" />
</File>


Add new web part dialog

Allright, now that we have a couple of things set up, lets add a little bit of code.  Inside of the CreateChildControls method that was created for you, put the following line of code.

this.Controls.Add(new LiteralControl("CreateChildControls"));

Then, paste in the following function.

protected override void RenderContents(HtmlTextWriter writer)
{
     writer.Write("Render Contents");
}

So we now are adding a control to the CreateChildControls function which will be rendered in the web part, displaying “CreateChildControls”.  But we also added a write statement to the RenderContents method… so what will happen?  Will both print?  Which one will print first?  Deploy it and find out (or scroll down just a little bit).  To deploy it, open the project settings and type in the url of your test server in the debug window.  Then clicking deploy in the top tool bar and deploy solution, it will be installed on your server.  Now go add it to a web part page like any other web part, easy as that.

So, that should have printed out “Render Contents”.  Now, stick the following line of code at the very beginning of the Render Contents Method.

base.RenderContents(writer);

So now it should print out “CreateChildControlsRender Contents”.  This is because before we did not include the base functions of the default RenderContents() method, which renders everything that was added in CreateChildControls().  This may seem useless, but it is important to understand what is being done where, and if nothing else, remember to call the base method when you override one.

Now, something that is very useful when developing web parts is to catch and display your error messages in the web part (Yes, you will make errors).  To do so, we need to catch the error and then add it as a literal to the web part.  Replace the contents of the CreateChildControls method with the following code to try it out.

try
{
     SPSite site = new SPSite("http:\\badurl");
     this.Controls.Add(new LiteralControl("CreateChildControls"));
}
catch (Exception Ex)
{
     this.Controls.Add(new LiteralControl(Ex.Message));
}

This should produce the following error message, unless your web application happens to be named badurl.
Web Part Error Catching

That is actually very useful and I recommend to always do it, and then maybe remove it once putting your code into production.  You could also put some friendly error message telling people to call IT if you see this message.

There is one other semi-cool thing I want to show you that can help when creating web parts.  We are going to enable Tracing for the page on which the web part was added.  This will show when each function was called and really helps track down bugs.  To turn on tracing, paste the code below into the try of the constructor of the web part.  Note that you will need to add trace statements like the one below to each of your methods for this technique to truly be helpful.

Context.Trace.IsEnabled = true;
Context.Trace.Write("WebPart", "Begining WebPartConstructor()");
Context.Trace.Write("WebPart", "EndingWebPartConstructor()");

Now redeploy the solution and scroll down in the page, pretty neat eh?  Below is a screen shot of what mine looks like in case you don’t feel like trying it.

Well, at least I think page level tracing is cool.  You can also turn it on for the entire site by modifying the web.config file, but that is another story.\

All good web parts have a custom editor in which you can specify any parameters or values you want.  After all, web parts are supposed to be generic and reusable right?  Below is the code you need to add an editor class to your project that inherits from the EditorPart class.  The first thing to do is add a blank c# class file to the project.  Add the first block of code below to it, erasing anything that may already be in the file.  Then, add the second block of code to the main c# file.

using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace WebPart2
{
    class myEditor : System.Web.UI.WebControls.WebParts.EditorPart
    {
        private TextBox _message;

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            _message = new TextBox();
            Controls.Add(_message);
        }

        public override bool ApplyChanges()
        {
            EnsureChildControls();
            HelloWorld webPart = WebPartToEdit as HelloWorld;

            if (webPart != null)
            {
                webPart.myMessage = _message.Text;
            }
            return true;
        }

        public override void SyncChanges()
        {
            EnsureChildControls();
            HelloWorld webPart = WebPartToEdit as HelloWorld;

            if (webPart != null)
            {
                _message.Text = webPart.myMessage;
            }
        }

    }
}
using System.Collections.Generic;
protected override void CreateChildControls()
{
    try
    {
        this.Controls.Add(new LiteralControl(myMessage));
    }
    catch (Exception Ex)
    {
        this.Controls.Add(new LiteralControl(Ex.Message));
    }
}

[WebBrowsable(false)]
public string myMessage { get; set; }

public override EditorPartCollection CreateEditorParts()
{
    List<EditorPart> editorParts = new List<EditorPart>();

    myEditor editor = new myEditor()
    {
        ID = this.ID + "_editorPart1",
        Title = "Test Editor"
    };

    editorParts.Add(editor);

    return new EditorPartCollection(editorParts);
}

This may seem like a lot, but it really isn’t too difficult.  Make sure that your namespaces match what your using in your project. Below is a screenshot of the working editor class, passing the value entered in the editor to the web part.

Now, if you look at the code in the Editor class, there are three main functions that you need.  The apply changes is called when you click apply or ok and it does what it says, it applies the changes.  The Sync changes kind of works the other way, pulling information from the web part into the editor class.  You can also override the same render stage methods in the editor class that you can in the web part to make your editor look more custom if you like. Also take note of the one method we added to the web part class. All this does is add your custom editor to the web part. You can set a few fields here like the title and description, but that’s pretty much it. Also important to notice is the attributes we set on the myMessage string in the web part class. This is required for the editor class to be able to retrieve its value. If you remove the line directly above it and declare it like a normal string, every time the editor window is opened any value previously entered into it will be lost.

Well, I am tired… and I the code is pretty self explanatory. Feel free to ask any questions if I failed to explain something. I think I will go over verbs in another posting and then get into some cooler, more usable examples. Web Parts in SharePoint 2007 and WSS 3.0 are much easier to get started than people think, and I encourage you to give them a shot.

You can download the web part project I went over above here.

Getting a list item’s attachments through code

By , August 10, 2009

So, I came across the requirement to create a list of links to all of the attachments of a list item in my custom aspx page. Seems easy right? I should be able to grab the list item and do something like item.Attachments to get a collection of some kind of SPAttachment Object… right? Well as it turns out, it’s not quite so simple.

SPListItem.Attachments returns a SPAttachmentCollection object which is fairly limited in what it allows you to do.  It does provide a simple way of adding and deleting attachments, but thats about it.  You can however treat the SPAttachmentCollection as if it was a StringCollection and enumerate through the collection as shown below to get the names of the files.

1
2
3
4
5
// item is a SPListItem
foreach (string attachmentName in item.Attachments)
{
     // attachmentName is the name of the attachment
}

Well that is better than nothing, but I needed links to the documents, not just a list of them. So the next thing we need to do is prefix the attachmentName string with the rest of the URL. It turns out that it is fairly simple to use a SPFolder object as seen below to grab the rest of the URL.

1
2
3
4
5
6
// item is a SPListItem, _Files is the Literal in my custom page
foreach (string attachmentName in item.Attachments)
{
     SPFolder attachments = item.ParentList.RootFolder.SubFolders["Attachments"].SubFolders[item.ID.ToString()];                                    
     _Files.Text += "<a href=\"https://SharePoint.com/" + attachments.Url + "/" + attachmentName + "\">" + attachmentName + "</a><br>";                              
}

So, while I don’t really like it, I think this is the easiest way of getting a link to the attachments for a given list item. If anyone has a better method, please feel free to share. Below is a little image of what resulting page may look like.

ListItemAttachments

Web Part Page Maintenance – Get rid of that broken web part

By , August 10, 2009

So, what happens when you are making a web part and despite your awesome coding prowess something goes wrong that prevents the page from rendering? It is kind of hard to change a setting on the web part when you can’t get to its editor window right? Well, the smart guys at Microsoft thought of this and included a “Web Part Page Maintenance” page for just such an occasion. At this page, you get a list of every web part that is added to the page and the ability to close, delete or reset them.

To get to this page, simply type “?contents=1″ at the end of the broken page URL.

Example: http://SharePoint/site.aspx is the page with the broken web part on it. Stick “?contents=1″ at the end of the URL to get http://SharePoint/site.aspx?contents=1

(Note: This will redirect the page to the layouts folder, opening spcontnt.aspx with the URL of the requesting page being sent in the new URL as a parameter. You could open this page directly, but its a lot easier to remember contents=1)

So, you will hopefully get a page like the one shown below. Now just delete the web part that is causing the problem and you are back in business.

Web Part Maintenance Page