Trouble shooting SPWeb object closed or disposed

22 May 2009

I recently came across an issue on a WCM site where the following error was being shown whenever a dropdown selection was changed on a custom web part:
 
SPException: Trying to use an SPWeb object that has been closed or disposed and is no longer valid 

This looked like the SPWeb object was being incorrectly disposed of but careful inspection of the web part showed that best practices for disposal of SPObjects had been followed .
 
To try and track down the cause of the error and to really satisfy myself that it wasn't the web part causing the issue I removed all references to SPWeb from the custom web part. The error was still appearing so this ruled out bad coding practice in this control.
 
The next step was to take a look at the other controls on the page. As this was a WCM site there were a number of custom controls being used for navigation and other functionality.
 
It didn't take too long to track down the culprit in a control being used to set the site title in the browser title bar. This contained the following:
 
using(SPWeb web = SPContext.Current.Web)
{
   //some code
}
 
When the dropdown selection was changed a postback was fired and this piece of code brought the site crashing down.
 
This was because both the using statement and the use of SPContext handle garbage collection so the SPWeb object was being disposed of twice and as it didn't exist on the second dispose the error above was thrown.
 
Once corrected the code looked like this:
 
SPWeb web = SPContext.Current.Web;
//some code 

Most of the links about this error on the web will point you towards the issue being incorrect disposal of objects but what is learnt here is that it might not be a coding issue in the control that seems to be causing the problem. In this case it was the postback being fired by the control rather than the control itself that was triggering the error. The root cause was actually a completely different web part on the page.

Twitter SharePoint web part - another update!

10 February 2009

** Update June 2010 - new Twitter web part using OAuth rather than Basic Auth **

When I mentioned that I was developing a Twitter web part to Mirjam van Olst she asked if it would be possible to work on it with me. So thanks to Mirjam, in the true spirit of international collaboration, we are now able to bring you an updated version of the web part which is more secure and easier to deploy.

Improvements include -

  • The password input now uses a password textbox to protect the Twitter credentials
  • TwitterLib.dll has been added to the wsp for easier deployment

Download the new and improved Dutch/British/Euro version here: TwitterPublicTimeline.wsp (24.25 kb)

Twitter SharePoint web part update

06 February 2009

** Update June 2010 - new Twitter web part using OAuth rather than Basic Auth **

Original post with deployment instructions

 The Twitter public timeline web part has now been updated with the following:

  • URLs in Tweets are displayed as active links
  • The user's screename links to their Twitter page
  • If @screename appears in the Tweet it is displayed as a link to the user's Twitter page

TwitterPublicTimeline.wsp (24.25kb)

Twitter SharePoint web part

04 February 2009

** Update June 2010 - new Twitter web part using OAuth rather than Basic Auth **

I thought I would have a go at creating a web part to display a Twitter public timeline within SharePoint. The reason for creating this web part is so that it can be used by project teams that are spread over several offices/countries to stay in touch and feel more connected without having to invest a lot of time emailing each other or talking on the phone. Twitter is ideal for this kind of light weight communication as it restricts the user to sending short, to the point messages.

Before starting I had a quick look on the web to see if I was reinventing the wheel. Michael Gannotti suggests this solution using javascript and the CEWP but I wanted something that we would have a little more control over in terms of html markup and branding and that wasn't limited to the CEWP being available. I also wanted to have the possibility of extending the web part to include other functionality in the future such as not just being able to display tweets but to also send them.

The web part is configurable using two custom attributes - username and password. This allows you to display any users public timeline assuming you have the password. To set it up for use with a project team public timeline you should create a Twitter account for the project and then follow the members of the team to see a timeline that displays tweets from each of the members. 

At the bottom of this post there are links to the .wsp file which can be deployed to SharePoint using stsadm.exe and a .css file so that you can see how I chose to style the web part but obviously you could brand it any way you want.

**Update by request - more detail on deploying solutions

My solution uses Twitterlib.dll which is an open source .Net wrapper for the Twitter API and was created by the developers at Witty. This is a link to the Witty project on Google code. 

Download the wsp for the Twitter web part: TwitterPublicTimeline.wsp (24 kb)

For a styling suggestion try this css: twitter.css (302.00 bytes)

Generic CSV or SQL data importer for SharePoint list

10 September 2008

UPDATE (09/10/09) - NEW AND IMPROVED VERSION HERE

I finally got bored of rewriting the same console application to move data from a csv or a sql table into a SharePoint list! The result is a generic console application that is capable of importing either a CSV file or some SQL data from a stored procedure. The app uses the object model so it needs to be run on the SharePoint server farm. I may get round to rewriting it using web services at some point. The CSV import parses the file so that things like line breaks and commas within fields are handled nicely. Any blank fields in the CSV do need to be filled using find and replace on blank space otherwise data ends up in the wrong columns.

To import a CSV the first row of the of the CSV file is used to define which columns the data will import to. Eg. A CSV that has one column with a header of Title will import the data into the Title column of the specified list. Modify the App.Config file to include the URL of your site collection, the list name, the path to the CSV and whether or not you want to delete all items in the list before importing.

To import SQL data create a stored procedure that returns the data as the names of the site columns

Eg. Select Name AS Title from tblPerson - will return one column of data that will import into the Title column of a list. Modify the App.Config to include the name of the stored procedure and the SQL connection string and run the app.

You can download the project from the following link:

AG.GenericSharePointListImporter.zip

This application is supplied as is and offers no guarantees feel free to use as you wish all I ask is that if you make any improvements then you share them in the comments or by email.

Web part custom property - dropdown list

19 December 2007

It isn't immediately obvious how to include a drop down list as a custom property on a web part. To do this you simply use an enum.

Eg.

//create enum

public enum ProductByEnum

{Type = 0,

Brand,

Chemistry};

//create get/set for the property

protected ProductByEnum productsBy;

[Personalizable(PersonalizationScope.User),WebBrowsable, WebDisplayName("Products By"),WebDescription("Use this property to change web part grouping")]public ProductByEnum ProductsBy

{

get { return productsBy; }

set { productsBy = value; }

}

A dropdown list will now appear in the miscellaneous section of your web part custom properties containing the enum values.

 

Creating XHTML compliant ASP.Net server controls

12 December 2007

ASP.Net is great but many of the controls use table tags when they render. I am currently in the process of developing some Internet sites using MOSS 2007 which need to meet accessibility guidelines so these controls, in their out of the box state, are no use to me. We have tried applying the CSS adapters that get rid of the tables but this also had the effect of removing tables from the site settings screens making them difficult to use.

The solution we are going for is to create new controls that inherit from the base control. The new control then overrides the render event to remove the non-compliant tags and replaces them with compliant ones.

We are also using this method to add script to the master pages which removes table tags from web part zones etc.

DISCLAIMER - I have created a non-tabular control for the SPGridView. You could argue that the SPGridView presents tabular data so does not need any changes to the rendered HTML, you would probably be right but this example shows what can be done. :-)

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Web.UI;
using System.Text.RegularExpressions;
using System.IO;

namespace XHTMLCompliantMOSSControls
{
    public class CompliantSPGridView : SPGridView
    {
        protected override void RenderContents(HtmlTextWriter output)
        {
            //get the rendered HTML
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            HtmlTextWriter hw = new HtmlTextWriter(sw);

            base.RenderContents(hw);
 
            //remove tables
            string str = sb.ToString();
          
            str = Regex.Replace(str, "<table[^>]*>", "<div class=\"mainSPGridView\">");
            str = Regex.Replace(str, "<tr>", "<div class=\"normalSPGridView\">");
            str = Regex.Replace(str, "<tr class=\"ms-alternating\">", "<div class=\"alternatingSPGridView\">");
            str = Regex.Replace(str, "</tr>", "</div>");
            str = Regex.Replace(str, "<td[^>]*>", "<div class=\"itemSPGridView\">");
            str = Regex.Replace(str, "</td>", "</div>");
            str = Regex.Replace(str, "<tr class=\"ms-viewheadertr\">", "<div class=\"headerSPGridView\">");
            str = Regex.Replace(str, "<th class=\"ms-vh2-nofilter ms-vh2-gridview\" scope=\"col\">", "<div class=\"itemSPGridView\">");
            str = Regex.Replace(str, "</th>", "</div>");
          
            output.Write(str);
        }
    }
}

If you then apply a bit of CSS using the classes that have been added it is possible to get it looking just like the tabular SPGridView.

This approach could be used with any server control to make it compliant with XHTML.

Excellent post about making SharePoint xhtml compliant

11 December 2007
For anyone using the web content management components of MOSS 2007 to produce Internet sites this is essential reading. SharePoint uses a lot of ASP.Net controls which render using tables and non compliant html. To get rid of this there are a few things you can do which are explained in this blog post http://zac.provoke.co.nz/archive/2007/04/19/guide-to-making-sharepoint-xhtml-compliant.aspx

An efficient way to set web control values

10 December 2007

Rather than setting the widths of label and textbox controls individually like this:

oLabel1.Width=150;

oLabel2.Width=150;

oLabel3.Width=150;

It is much more efficient to add the controls to the controls collection and use:

foreach(Control oControl in this.Controls)
{
     if (oControl.GetType().ToString() == "System.Web.UI.WebControls.Label")
     {
       Label oLabel = (Label)oControl;
       oLabel.Width = 120;
     }
}

This then allows you to change the widths of all your labels within the page or web part in one place. This approach can also be taken with other controls like text boxes and drop downs or could be used to set other properties such as font or color.

Or you could just use CSS.  Smile

Setting custom properties on web parts

03 December 2007

When creating web parts it is often useful to allow users to supply some additional parameters to the web part. This can be done by adding custom attributes which can then be set by the user and used in your code.

To do this use the following syntax:

   [Personalizable(PersonalizationScope.User),
         WebBrowsable, WebDisplayName("Products List"),
         WebDescription("Use this property to change list used to retrive products from")]
        public string ProductList
        {
            get { return strProductsList; }
            set { strProductsList = value; }
        }

In this case, rather than hard coding the name of the products list, the user is able to specify which list to use.