Disposing SPRequest

by Danielvg 17. January 2011 22:20
I was recently asked about the disposing of SPRequest related objects like SPWeb and SPSite, since I was unsure on some of the questions I decided to do some small examples to determine when the following two errors related to disposing of SPRequest show in the ULC:
 
Error 1, Unexpected:
Detected use of SPRequest for previously closed SPWeb object.  Please close SPWeb objects when you are done with all objects obtained from them, but not before.
 
Error 2, High:
An SPRequest object was not disposed before the end of this thread.  To avoid wasting system resources, dispose of this object or its parent (such as an SPSite or SPWeb) as soon as you are done using it.
 
 
Test case Result Id*
public void TestOne() 
{ 
    using (var site = new SPSite(SPContext.Current.Web.Url)) 
    using (var web = site.OpenWeb()) 
    { 
        this.Literal1.Text = web.Title; 
    } 
}
Nothing  
public void TestTwo() 
{ 
    var site = new SPSite(SPContext.Current.Web.Url); 
    var web = site.OpenWeb(); 
    this.Literal1.Text = web.Title; 
}
Error 2
120
110
public void TestThree() 
{ 
    this.Literal1.Text = TestThreeHelper().Title; 
}


public SPWeb TestThreeHelper() 
{ 
    using (var site = new SPSite(SPContext.Current.Web.Url)) 
    using (var web = site.OpenWeb()) 
    { 
        return web; 
    }
}
Error 1
 
public void TestFour() 
{ 
    var site = new SPSite(SPContext.Current.Web.Url); 
    using (var web = site.OpenWeb()) 
    { 
        site.Dispose(); 
        this.Literal1.Text = web.Title; 
    } 
}
Error 1
 
public void TestFive() 
{ 
    SPWeb web = null; 
    using (var site = new SPSite(SPContext.Current.Web.Url)) 
    using (web = site.OpenWeb()) 
    { 
    } 
    this.Literal1.Text = web.Title; 
}
Error 1
 
public void TestSix() 
{ 
    using (var site = new SPSite(SPContext.Current.Web.Url)) 
    { 
        var web = site.OpenWeb(); 
        this.Literal1.Text = web.Title + "test3"; 
    } 
}
Nothing
(SPSite disposes all sub webs, including rootWeb)
120
public void TestSeven() 
{ 
    SPList list = null; 
    using (var site = new SPSite(SPContext.Current.Web.Url)) 
    using (var web = site.OpenWeb()) 
    { 
        list = web.Lists["SomeList"]; 
    } 
    this.Literal1.Text = list.Title; 
}
Error 1
 
public void TestEight() 
{ 
    SPListItem item; 
    using (var site = new SPSite(SPContext.Current.Web.Url)) 
    using (var web = site.OpenWeb()) 
    { 
        var list = web.Lists["SomeList"]; 
        item = list.Items[0]; 
    } 
    this.Literal1.Text = item.Title; 
}
Nothing
(Some properties of SPListItem can be used, however other will reopen the Site, Web and list)
 
public void TestNine() 
{ 
    var site = new SPSite(SPContext.Current.Web.Url); 
    using (var web = site.OpenWeb()) 
    { 
        this.Literal1.Text = web.Title; 
    } 
}
Nothing
(I am pretty sure this will cause an Error 2 like problem when the thread that created the site ends)
110
public void TestTen() 
{ 
    using (var web = TestTenHelper()) 
    { 
        this.Literal1.Text = web.Title; 
    } 
}

public SPWeb TestTenHelper() 
{ 
    var site = new SPSite(SPContext.Current.Web.Url); 
    var web = site.OpenWeb(); 
    return web; 
}
Nothing
(Same as test nice)
120
110
*SPDisposeChecker warning id
I must admit that I am surprised about some of the results, but this at least clears everything up for me. Following is an example of how some of these errors can be resolved:
 
public void TestTreeFix() 
{ 
    Action<SPWeb> action = (openWeb) => { this.Literal1.Text = openWeb.Title; }; 
    TestTreeHelperFix(action); 
}

public void TestTreeHelperFix(Action<SPWeb> action) 
{ 
    using (var site = new SPSite(SPContext.Current.Web.Url)) 
    using (var web = site.OpenWeb()) 
    { 
        action(web); 
    } 
}
 
Dispose them objects! Else you will end up with no available ports and a starving farm!

SharePoint: Show Ribbon by Default

by Danielvg 11. July 2010 10:53

While working on a project at work I got a Bug work item that said “Ribbon is not shown by default when a new web is created”. Long story short the project involves a custom way of creating new webs in SharePoint, the webs are based on a publishing web but the Ribbon is not shown when the web is created and the users have to click “show Ribbon” which is not desired.

Sadly google/bing was no help so I had to turn to some Javascript debug and reflector to solve to problem. It got me to a property called “__DisplayShowHideRibbonActionId” that is not in a webs propertybag by default and when set to false the ribbon is shown to all users.

Simple code snippet of how this could be implemented(demo code, should not be used in production):


public static string CreateWeb(SPWeb parentWeb, string title, string webTemplate)
{
    parentWeb.AllowUnsafeUpdates = true;
    using (SPWeb newWeb = parentWeb.Webs.Add(title, title, string.Empty, parentWeb.Language, 
                                                              webTemplate, false, false))
    {
        // Show Ribbon by default
        newWeb.AllProperties["__DisplayShowHideRibbonActionId"] = false.ToString();
        newWeb.Update();
        return newWeb.Url;
    }
}

It feels a bit hackish to do it this way, so if anyone knows of a better way to make the ribbon visible when a web is created then please to tell :)

Trying SharePoint 2010 Client Object Model

by Danielvg 15. December 2009 23:42

Having done some projects that that use the standard web services in SharePoint 2007 I was really looking forward to try this new feature in SharePoint 2010! Here are some of the CRUD stuff I played around with:

The basic concept for retrieving and reading data:


// Create a client context based on the full web url of the SharePoint server
var context = new ClientContext("http://192.168.0.125");
// Set the object to load default values for
context.Load(context.Web);
//Execute the queue (Get data from the server)
context.ExecuteQuery();
// You can now use default properties of the web object
MessageBox.Show(context.Web.Title);

As the code comment says, when you define a web to be loaded all the default/standard properties are loaded into the web object, though this does not include lists, sites etc., if you only want to load a few properties to save some bits the load call can be made with:


// Load only Title and Id from the Web
context.Load(context.Web, w => w.Title, w => w.Id);

If an unloaded property is called a “PropertyOrFieldNotInitializedException” will be thrown.

Here is another example that shows how to retrieve contacts from a SharePoint contact list, that has an “e” in the first name, the list name is “EmployeeList”


var context = new ClientContexthttp://192.168.0.125);
// Notice the different load call, LoadQuery can make use of LINQ
var lists = context.LoadQuery(context.Web.Lists.Where(l => l.Title == "EmployeeList"));
context.ExecuteQuery();
var employeeList = lists.SingleOrDefault();
var query = new CamlQuery { ViewXml = "<View><Query><Where><Contains>"
    +"<FieldRef Name='FirstName'/><Value Type='Text'>e</Value>"
    +"</Where></Contains></View></Query>" };
var items = employeeList.GetItems(query);
context.Load(items);
context.ExecuteQuery();

var nameList = new List<string>();
items.ToList().ForEach(i=> nameList.Add(i["FirstName"].ToString()));
employeeListBox.ItemsSource = nameList;

As you can see, you can pretty much dig deep into the SharePoint site before executing the first query, it seems very efficient and is much faster to work with when compared to the old standard web services. But sadly I do not think there is a way to use LINQ for list items and folders, so (at least for now) CAML is still alive and kicking on the client side. If you do not need to filter your items or folders there are some standard queries in the CamlQuery entity.


var itemsQuery = CamlQuery.CreateAllItemsQuery();
var folderQuery = CamlQuery.CreateAllFoldersQuery();

The result from the above code with the CAML filter:

image

After retrieving an item we can update its properties by simply setting them and calling update (continuing the code from above):


items[0]["FirstName"] = "UpdatedFirstName";
items[0].Update();
context.ExecuteQuery();

And now the first name of item[0] is updated

image

And if you want to delete a list item, it is just as easy:


items[0].DeleteObject();
items[0].Update();
context.ExecuteQuery();

A few pros about the new Client OM:

  • Same API structure as the server side API
  • Works with managed .Net Applications, Silverlight applications and JavaScript
  • Highly productive compared to the old web services
  • Easy to limit bits sent over the wire
  • JSON Server response
  • Lowers the need for CAML

For more information about the new Client OM see msdn

Trying LINQ To SharePoint (2010)

by Danielvg 7. December 2009 09:30

Having only tried LINQToSharePoint (the 2007 codeplex version) a few times I decided to make a small test application of the new 2010 version, and here is the result:

I used a newly created contact list located at the root site, called EmployeeList, with 3 dummy objects for the test:image

Since there is no GUI to create proxy classes, as with the early versions of LINQ to SQL, spmetal is used to create the proxy classes. Running SPMETAL with the following arguments creates the proxy classes in the Demo.LinqToSharePoint namespace:

SPMETAL /web:http://win-o6kbvml4ahk /code:DemoSite.cs /language:csharp /namespace:Demo.LinqToSharePoint

spmetal basically crawls the site you give it and creates entities for each list in the site and as with LINQ to Sql you also get a context that has the expected functionality. See msdn for a full list of command line options that spmetal takes.

Creating a visual webpart project in VS2010 and adding the newly created DemoSite.cs file is just about all it takes to test out the feature! Oh and remember to add a reference to Microsoft.SharePoint.Linq (it can be located in %ProgramFiles%\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI), or you will get a lot of errors (216 in my case)

The test code to actually use LINQ to SharePoint looks like this:


using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using System.Linq;

namespace Demo.LinqToSharePoint.LinqToSharePointDemo
{
    public partial class LinqToSharePointDemoUserControl : UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var context = new DemoSiteDataContext("http://win-o6kbvml4ahk");
            var employees = from employee in context.EmployeeList select employee.FirstName;
            EmployeeListBox.DataSource = employees;
            EmployeeListBox.DataBind();
        }
    }
}

And the webpart shows:

image

That is about it, really easy to use and it will clearly save a lot of time, bye bye CAML! I wonder if the VS team is planning the same GUI as with LINQ To Sql, it would make this “new” feature even better!