search blog
most popular
MCP MCTS MCT MVP

WSPBuilder - Walkthrough of the Visual Studio Add-in

Author: Tobias Zimmergren
http://www.zimmergren.net

Introduction

Alright. People have approached me lately and asked me if I could give them a brief introduction to the WSPBuilder extensions available for Visual Studio. Instead of taking all those discussions on one by one, I've decided to document some of the main features here. If I'm missing out on something, please let me know and I'll fill it up.

Bil Simser did a survey with the SharePoint MVP's and summarized the foremost favorite CodePlex projects in this article. 

In this article I will cover one of my favorite tools - WSPBuilder.

WSPBuilder background

A SharePoint Solution Package (WSP) creation tool for WSS 3.0 & MOSS 2007
No more manually creating the manifest.xml file
No more manually specifying the DDF file
No more using the makecab.exe application

Carsten Keutmann, an MVP and friend in Copenhagen is the brilliant mind behind this awesome application.

The idea behind the WSPBuilder add-in for Visual Studio is that it's based on any normal "Class library" template - which means that you can easily copy your entire WSPBuilder project to a machine that doesn't have WSPBuilder and still be able to open the project. - This is something you can't do with a lot of other extension tools (say, the VSeWSS for example)

WSPBuilder Installation

Just download the latest release of the "WSPBuilder Extensions - Visual Studio Addin" and let the installation guide take you through the most simple process ever - clickety click.

Creating a WSPBuilder project

When you have installed the add-in to Visual Studio, you should now be able to create a new project based on the "WSPBuilder" template.

To kick this off, let's create our WSPBuilder project:
image

Note: You don't have to create a WSPBuilder template, you can create a normal Class Library as well. The only thing about a WSPBuilder template is that it will automatically create the "12" folder along with a temporary strong-key so you don't have to do that right now.

When you've created the project, you'll see a structure like this one in your solution explorer:
 image

The WSPBuilder will create the 12-folder, since it's good practice to start your projects from the 12-root. It will also add the file "solutionid.txt" which contains a GUID to be used on the .wsp package, for easy reference. You will also get a strong-key generated for you so you don't have to worry about signing your project right now.

Alright, now that we're up and running with a blank WSPBuilder project - we should start by adding something to the solution.

WSPBuilder Templates - Overview

In an ordinary fashion, right click on the project and choose Add - New item.
image

Choose the "WSPBuilder" node and you will see an overview over the available templates like this:
image

Let's walk through each and every one of them! The joy! :-)

Blank Feature Template Overview

A blank feature does exactly what the name implies, it creates a blank feature for you!

I'm creating a blank feature, and naming it to "BlankFeature1" so we easily can distinguish it from the other folders created later on.

With WSPBuilder, when you create a new item based on a template, you'll get a dialog asking you for some variables - and since this is a feature, it's going to need a Title, Description and of course a Scope:
image

Your solution tree will be populated with a few new things, in this case the BlankFeature1 that we chose to create:
image

As you will see, you get not only the perfectly correct 12-hive structure - you will also get the feature.xml and elements.xml files created for you, and the feature.xml file can look like this:

<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="8e039720-d7df-460a-8d65-c52e47417fdf"
          Title="BlankFeature1"
          Description="Awesome description for BlankFeature1"
          Version="12.0.0.0"
          Hidden="FALSE"
          Scope="Web"
          DefaultResourceFile="core"
          xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>   
  </ElementManifests>
</Feature>

Event Handler Template Overview

With the Event Handler item template, you will not only get the correct 12-structure in your solution - you will also get the reference to "Microsoft.SharePoint.dll" added automatically, since an event handler requires some talking to the SharePoint Object Model.

We will get our feature.xml and elements.xml as normal - but this time the elements.xml is pre-populated with some tags to hook up our event handler:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="100">
    <Receiver>
      <Name>AddingEventHandler</Name>
      <Type>ItemAdding</Type>
      <SequenceNumber>10000</SequenceNumber>
      <Assembly>Zimmergren.SharePoint.Demo.WSPBuilder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7201b5590fd1fc0</Assembly>
      <Class>Zimmergren.SharePoint.Demo.WSPBuilder.EventHandler1</Class>
      <Data></Data>
      <Filter></Filter>
    </Receiver>
  </Receivers>
</Elements>

As you can see, the elements.xml file is referring to the assembly called Zimmergren.SharePoint.Demo.WSPBuilder and a class called EventHandler1.

With the magic of WSPBuilder, this class has of course also been created for us and will look something similar to this:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace Zimmergren.SharePoint.Demo.WSPBuilder
{
    class EventHandler1 : SPItemEventReceiver
    {
        public override void ItemAdded(SPItemEventProperties properties)
        {
            base.ItemAdded(properties);
        } 

        public override void ItemAdding(SPItemEventProperties properties)
        {
            base.ItemAdding(properties);
        } 

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            base.ItemUpdated(properties);
        } 

        public override void ItemUpdating(SPItemEventProperties properties)
        {
            base.ItemUpdating(properties);
        } 
    }
}



Solution Installer Configuration

If you've ever used the SharePoint Installer from CodePlex, you know that when you want to use it with your own .wsp file you need to do some adjustments to the configuration xml.

With the Solution Installer Configuration template you will get this configuration automatically created and hooked up with your project. The Setup.exe.config file might look like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="BannerImage" value="Default"/>
    <add key="LogoImage" value="None"/>
    <add key="EULA" value="EULA.rtf"/>
    <add key="SolutionId" value="6e23b11d-8460-49a0-b2f1-b8aa78d7c58d"/>
    <add key="FarmFeatureId" value="bb1586eb-3427-483b-baa5-ae5498c47d69"/>
    <add key="SolutionFile" value="Zimmergren.SharePoint.Demo.WSPBuilder.wsp"/>
    <add key="SolutionTitle" value="Zimmergren.SharePoint.Demo.WSPBuilder"/>
    <add key="SolutionVersion" value="1.0.0.0"/>
    <add key="UpgradeDescription" value="Upgrades {SolutionTitle} on all frontend web servers in the SharePoint farm."/>
    <add key="RequireDeploymentToCentralAdminWebApplication" value="true"/>
    <add key="RequireDeploymentToAllContentWebApplications" value="false"/>   
  </appSettings>
</configuration>



Web Part Feature

This is by far one of the most popular templates, as it crates a generic template for your web part and also creates the feature for provisioning the Web Part to the Web Part Gallery.

You will get the elements.xml file configured something like this:

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="WebPartPopulation" Url="_catalogs/wp" RootWebOnly="TRUE">
    <File Url="WebPartFeature1.webpart" Type="GhostableInLibrary">
      <Property Name="Group" Value="MyGroup"></Property>
      <Property Name="QuickAddGroups" Value="MyGroup" />
    </File>
  </Module>
</Elements>

and you'll get the required .webpart file configured something like this:

<?xml version="1.0" encoding="utf-8" ?>
<webParts>
  <webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
    <metaData>
      <type
        name="Zimmergren.SharePoint.Demo.WSPBuilder.WebPartFeature1,
        Zimmergren.SharePoint.Demo.WSPBuilder,
        Version=1.0.0.0,
        Culture=neutral,
        PublicKeyToken=b7201b5590fd1fc0" />
      <importErrorMessage>
            Cannot import WebPartFeature1 Web Part.
      </importErrorMessage>
    </metaData>
    <data>
      <properties>
        <property name="Title" type="string">WebPartFeature1</property>
        <property name="Description" type="string">
            Description for WebPartFeature1
        </property>
      </properties>
    </data>
  </webPart>
</webParts>

and you will get the WebPartFeature1.cs file created automatically (or whatever you choose to name it) and it usually look like this:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;

namespace Zimmergren.SharePoint.Demo.WSPBuilder
{
    [Guid("a043d73d-7418-4918-baed-828a2bc77019")]
    public class WebPartFeature1 : Microsoft.SharePoint.WebPartPages.WebPart
    {
        private bool _error = false;
        private string _myProperty = null; 

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("My Property Group")]
        [WebDisplayName("MyProperty")]
        [WebDescription("Meaningless Property")]
        public string MyProperty
        {
            get
            {
                if (_myProperty == null)
                {
                    _myProperty = "Hello SharePoint";
                }
                return _myProperty;
            }
            set { _myProperty = value; }
        } 

        public WebPartFeature1()
        {
            this.ExportMode = WebPartExportMode.All;
        } 

        /// <summary>
        /// Create all your controls here for rendering.
        /// Try to avoid using the RenderWebPart() method.
        /// </summary>
        protected override void CreateChildControls()
        {
            if (!_error)
            {
                try
                { 

                    base.CreateChildControls(); 

                    // Your code here...
                    this.Controls.Add(new LiteralControl(this.MyProperty));
                }
                catch (Exception ex)
                {
                    HandleException(ex);
                }
            }
        } 

        /// <summary>
        /// Ensures that the CreateChildControls() is called before events.
        /// Use CreateChildControls() to create your controls.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            if (!_error)
            {
                try
                {
                    base.OnLoad(e);
                    this.EnsureChildControls(); 

                    // Your code here...
                }
                catch (Exception ex)
                {
                    HandleException(ex);
                }
            }
        } 

        /// <summary>
        /// Clear all child controls and add an error message for display.
        /// </summary>
        /// <param name="ex"></param>
        private void HandleException(Exception ex)
        {
            this._error = true;
            this.Controls.Clear();
            this.Controls.Add(new LiteralControl(ex.Message));
        }
    }
}



Web Service Template

The following files will be automatically created for you:

  • 12\LAYOUTS\WebService1.asmx
  • WebServiceCode\WebService1.cs

WebService1.asmx may look like this:

<%@ WebService Language="C#"
Class="Zimmergren.SharePoint.Demo.WSPBuilder.WebService1,
Zimmergren.SharePoint.Demo.WSPBuilder,
Version=1.0.0.0,
Culture=neutral,
PublicKeyToken=b7201b5590fd1fc0"  %>

WebService1.cs may look like this:

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

namespace Zimmergren.SharePoint.Demo.WSPBuilder
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class WebService1 : System.Web.Services.WebService
    { 

        public WebService1()
        { 
        } 

        [WebMethod]
        public string HelloWorld()
        {
            return "Hello World";
        } 
    }
}



Custom Field Type Template

The Custom Field Type template will create all the necessary files to get up and going with a Custom Field Control.

The following files will be generated and populated:

  • 12\TEMPLATE\CONTROLTEMPLATES\CustomFieldType1FieldEditor.ascx
  • 12\TEMPLATE\XML\fldtypes_CustomFieldType1.xml
  • FieldTypeCode\CustomFieldType1.cs
  • FieldTypeCode\CustomFieldType1Control.cs
  • FieldTypeCode\CustomFieldType1FieldEditor.cs

The contents in these files are too much to bring up in a single blogpost, so if you're thrilled about seeing what they look like - create your own project and dig in :-)

Feature With Receiver

Does what it says it's supposed to do. Creates a FeatureReceiver and all required files.

  • 12\TEMPLATE\FEATURES\FeatureWithReceiver1\elements.xml
  • 12\TEMPLATE\FEATURES\FeatureWithReceiver1\feature.xml
  • FeatureCode\FeatureWithReceiver1.cs

Feature.xml might look like this:

<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="3e724aaf-c1ed-4a93-ae1c-c6d3f59b2214"
          Title="FeatureWithReceiver1"
          Description="Description for FeatureWithReceiver1"
          Version="12.0.0.0"
          Hidden="FALSE"
          Scope="Web"
          DefaultResourceFile="core"
         ReceiverAssembly="Zimmergren.SharePoint.Demo.WSPBuilder,
         Version=1.0.0.0,
        Culture=neutral,
        PublicKeyToken=b7201b5590fd1fc0"
      ReceiverClass="Zimmergren.SharePoint.Demo.WSPBuilder.FeatureWithReceiver1"
        xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>
  </ElementManifests>
</Feature>

FeatureWithReceiver1.cs might look like this:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace Zimmergren.SharePoint.Demo.WSPBuilder
{
    class FeatureWithReceiver1 : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            throw new Exception("The method or operation is not implemented.");
        } 

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            throw new Exception("The method or operation is not implemented.");
        } 

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
            throw new Exception("The method or operation is not implemented.");
        } 

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}

Sequential Workflow Feature and State Machine Workflow Feature Templates

Creates the necessary files to get started with your Sequential Workflow code.

  • 12\TEMPLATE\SequentialWorkflowFeature1\elements.xml
  • 12\TEMPLATE\SequentialWorkflowFeature1\feature.xml
  • WorkflowCode\SequentialWorkflowFeature1.cs
  • WorkflowCode\SequentialWorkflowFeature1.designer.cs

The same routine applies to the State Machine Workflow Feature template.

 

Web Part Without Feature

Finally, you can create a Web Part without the feature - basically just creating the .webpart file and the .cs file.

  • 80\wpcatalog\WebPart1.webpart
  • WebPartCode\WebPart1.cs

Solution tree overview

Since I've been bashing all kinds of templates in here, you'll see that there's a huge tree of files - all automatically created in less than 1 minute.

image

Template Overview Summary

Alright, the templates I've been mentioning before are great to get rolling with a new SharePoint project. But what about deployment of this solution? How do we create our .wsp file, and how do we choose where the files should land (Global Assembly Cache - GAC - or the /bin folder?)

That's what the next section is all about - bringing some clarification to how the WSPBuilder creates your packages.

WSP Creation and Deployment with WSPBuilder

So, when we're satisfied with our awesome project and want to build a .wsp package from it - we can simply choose to right click the project -> WSPBuilder -> Build WSP and it will automatically create the .wsp for us:
image

This will create a .wsp file in your project folder like so:
image

Now, if you want to check the contents of the .wsp package, you simply rename the .wsp file to .cab and open it, like so:
image

Manifest.xml

In the cabinet (.wsp package) you will find the file called Manifest.xml - this is the file that tells SharePoint where to actually deploy the solution - GAC or BIN.

If you don't do any changes at all, this file will look something like this:
image

As you can see, the DeploymentTarget is set to "GlobalAssemblyCache"  and your dll will go into the GAC.

Now, in this particular case we can not deploy to the /bin folder anyway - as we have types in our assembly that MUST go into the GAC (Workflows and EventReceivers are two of those types).

But if we were to have a Web Part project or what not - and we want to deploy it only to the /bin folder, follow along with the next few steps.

Scoping the assembly for BIN instead of GAC (including Code Access Security generation)

Okay. So you don't want it in the GAC, but in your BIN folder instead. That's okay, just follow along with these few simple steps:

  • Remove your /bin/debug folder entirely from your solution (make sure the .dll gets wiped)
  • If the 80-folder in your project root isn't created - create it
    • Create a folder called "bin" folder in the 80 folder
    • Your solution tree should look something similar to this:
      image
    • Right click your project and choose "Properties"
    • Choose the "Build" tab
    • Change the Output path from "bin\Debug" to "80\bin\":
      image

When you build your project now, your .dll should pop into the "80\bin\" folder in your solution tree like this:
image

Ready to Rock - Scoping the assembly for the /bin folder

If we go about building our .WSP package again (right click project - WSPBuilder - Build WSP) and rename the .wsp to .cab and check the manifest.xml file - we should see two things done different:

  • DeploymentTarget is set to WebApplication (any chosen WebApp, e.g. /bin)
    image
  • Some general CAS (Code Access Security) permissions has been automatically added to make your assembly run:
    image

Deployment with WSPBuilder

Okay. So we've created our project, scoped it either for GAC (do nothing) or for /bin (make the changes in the previous section) - and we want to deploy it. What do we do?

  • Right Click the Project -> WSPBuilder -> Deploy
    Your output window will show something like this:
    image

Check your Solution Management in Central Administration under the tab "Operations" and make sure it's successfully deployed:
image

Conclusion and Summary

This post simply walks through some of the more popular features of the WSPBuilder created by my pal Carsten Keutmann in Copenhagen.

If there's any questions or comments - please add them in the comments section below.

Thanks


Published: Apr-08-09 | 167 Comments | 0 Links to this post

How To: SharePoint and Silverlight 2.0 – Part 1

Author: [MVP] Tobias Zimmergren
Web: http://www.zimmergren.net

Prephase

I have previously written up a few articles on how you can get more from your SharePoint environment by enhancing it with AJAX, .NET 3.5 and Silverlight.

References to those articles can be found here:

My intention is to get a SharePoint / Silverlight article series going, and this is to be the first article in the series – How to get up and running!

Prerequisits

Must have:

Note: I’m not going to describe how you create a .xap file – you’ll find plenty of resources for that on the net. Just go google! (Live.com, yeah!)

Nice to have:

Part 1 – Step by step to configure your SharePoint environment for Silverlight 2.0

First of all, if you don’t want to do the manual .NET 3.5 settings in your web.config – there’s a great feature to take care of this on CodePlex which can be found under the Features project.

Step 1: Download, install and deploy the .NET 3.5 Web Config feature
  • Download the .NET 3.5 web.config feature from here
  • Install the .wsp into your SharePoint environment
  • Deploy the .wsp into your SharePoint environment to the appropriate Web Application
    image
  • Activate the feature for your Web Application (the one you deployed to)
    (This is done from Central Administration – Application Management – Manage Web Application Features)
    image 

Now we’re all set with the pre-configurations of the web.config – though there’s one more thing we need to manually do.

Step 2: Adding the final touches to web.config manually

Since the features project doesn’t include Silverlight by default (except for the Beta 2 version, which we’re not interested in..) you should now open up your web.config manually and

  • add the following line to <system.web> <compilation> <assemblies>:

<add assembly="System.Web.Silverlight,
    Version=2.0.5.0,
    Culture=neutral,
    PublicKeyToken=31bf3856ad364e35" />

It should look something like this:
image

Step 3: Add System.Web.Silverlight.dll to the GAC (Global Assembly Cache)

Add the System.Web.Silverlight.dll to the Global Assembly Cache (either drag’n’drop it into C:\Windows\assembly or use Gacutil.exe or use the default .NET Configuration Tool)

You’ll find the System.Web.Silverlight.dll assembly in the Silverlight 2.0 SDK folder, located here:

C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Server\

Step 4: Set the correct MIME-type for the Silverlight .xap filetype

Go to your IIS management console (Start – Run - “inetmgr” without the quotes)

  • Select your Web Application from the list, and select properties:
    image
  • Choose “HTTP Headers” and then “MIME Types…”
    image
  • Add the MIME-type for Silverlight 2.0 Applications as shown:
    image
  • Okay, Okay, Okay (Press the buttons..)
  • Close the IIS manager as we will not need it anymore for the time being!

Now when all those fancy-pancy things are done – let’s get rolling with creating a simple Hello World Web Part using Silverlight 2.0, shall we?

Part 2 – Creating a first Web Part to host a Silverlight application

If you’ve read this far you should now be set up properly to create a Silverlight Web Part (Really, a Web part that loads the silverlight application and renders in the browser)

Step 1: Visual Studio 2008 time!

First of all, make sure you’ve got the .xap file in handy, then launch Visual Studio 2008 SP1.

  • Create a new Web Part project in your desired fashion – I’m using the WSS Extensions for ease:
    image
  • Add a reference to the System.Web.Silverlight assembly and to the System.Web.Extensions assembly, it should look something like this:
    image
     
  • Add the following using statements:
    Note: I’ve stripped down the default using statements, as they’re overkill for this – this is what you should need

    using System.Runtime.InteropServices;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.SilverlightControls;


  • Make an override on the OnInit method (We will dynamically add a ScriptManager to the current page, if there’s not one already):

    protected override void OnInit(System.EventArgs e)
    {
        base.OnInit(e);
        var sm = ScriptManager.GetCurrent(Page);
        if(sm == null)
        {
            var scriptManager = new ScriptManager();
            scriptManager.EnablePartialRendering = true;
            Page.Form.Controls.AddAt(0,scriptManager);
        }
    }

  • Write the following very simple code to load a Silverlight class into the Web Part, set it’s source to our .xap file and simply add it to the controls collection:  

    private Silverlight mySLControl;
    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        mySLControl = new Silverlight
        {
            ID = "HelloSilverlightControl",
            Width = new Unit(367), 
            Height = new Unit(150),
            Source = @"/_layouts/ZimmerLight/Hello/Hello.xap"
        };
        Controls.Add(mySLControl);
    }

  • Build and deploy the Web Part, and cross your fingers!
    (Using the WSS Extensions for Visual Studio, just rightclick the project and choose Deploy)
    image 
Step 2: Add the Web Part to a page
  • I’ve put my Web Part in a “Silverlight Web Parts” group – simply choose it and click add.
    image 
  • Voila, a fully functional Silverlight 2.0 Web Part rendered inside SharePoint – without any trouble!
    image


Summary and Download

As you’ve seen in this article, it isn’t too hard to get up and running with Silverlight 2.0 (and .NET 3.5 of course) and get our first Silverlight 2.0 Web Part spinning in SharePoint.

You should now be able to:

  • Configure your environment to use Silverlight 2.0
  • Hook up your Silverlight Application(s) in SharePoint
  • Enjoy the richness of Silverlight in SharePoint!

You can download the Visual Studio project from here

Comments and Feedback appreciated

Please leave your print in the comments, feedback is always nice :-)


Published: Dec-10-08 | 23 Comments | 0 Links to this post

CKS EBE – Comments Manager

Introduction

<EDIT>
    A new version of this tool can be downloaded [here]
    Read more about the new version [here]
</EDIT>

I have been getting a few requests from people who've been getting quite a lot of spam in their Enhanced Blog Edition SharePoint blog, and who don’t currently have the ability to change any code or make adjustments. (They’ve got permissions to the system, but not to actually do anything like upgrade the assembly, add a nifty re-captcha validator or any other changes. They’re only allowed to do the “admin-stuff through the admin-interface”).

My quick and dirty solution was to provide them with a “Comments Manager” which basically is a Windows Application that will list all comments in the blog with a checkbox beside it. The “admin” can then check the desired (or, undesired..) blog comments and then kill them. This solution proved to be much faster than to do the same using the web browser using e.g. the tedious “Edit in datasheet view” option.

Note; This isn’t by far any cool application – it merely does what the few people want it to do, kill undesired comments with a better overview :)

Features

This light-weight application will do the following:

  • List all comments
    • Comment Author
    • Trimmed Body
    • Background-coloring
      • Green for comments with status = “Approved”
      • Red for all other (Rejected and Pending)
  • Kill selected comments

Simple as that!

Comments Manager preview

image

Download

Download the CKS:EBE Comments Manager v1.1.0.0

If you have ideas or comments, or if it simply doesn’t work – leave a comment!
Better yet, leave a comment anyway! :)

Future additions

If required by the people using this simple app – the future versions could include

  • Comment status change [Approval status]
  • Use Web Services to connect to your SP site instead
  • Track- and linkback manager
  • etc. etc.


Published: Oct-16-08 | 4 Comments | 0 Links to this post

Web Part Caching – A simple approach

All kudos to Vince Rothwell who provided an awesome blogpost on SharePoint Caching and the CacheDependency object

This week I am tutoring a SharePoint 2007 development class over at Informator in Gothenburg, Sweden. Today we’ve been looking at Web Parts, creation of custom webparts and best practices for creating our custom solutions based on web parts.

I quickly coded up a sample which is caching items in a webpart - Huge server load is a major impact point for some organizations, making caching a strategically important choice if there’s much redundancy.

Anyway, you probably already know that it’s a good thing to cache your data once in a while if you’ve got heavy load and the data isn’t any “to-the-minute” critical information. So let’s get on with it..

Why?

Since people have been asking for a ‘simple sample’ of how to cache things in SharePoint – I thought that I would provide just that, a simple sample. For more in-depth information about caching and cachedependendies, check out Vince’s blog.

Check it out!

Web Part fetching items from a SPWeb object, looping all SPList objects and displaying the ItemCount property.

If there isn’t a cache object present, the iteration of the lists will be done immediately
image

If there is a cache object present, it will fetch the information from the cached object instead of iterating the lists, saving us some resources 
image

Code It!

This is the full code of the simple sample cache Web Part:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using Microsoft.SharePoint;
using System.Web;
namespace Zimmergren.WebParts.SampleCachePart
{
    public class SimpleCache : System.Web.UI.WebControls.WebParts.WebPart
    {
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            base.Render(writer); 

            List<SPList> lists = new List<SPList>();
            string status = ""; 

            if (HttpRuntime.Cache["SimpleSampleCache"] == null)
            {
                status = "The following items are <strong>NOT</strong> fetched from the cache<br/><br/>"; 

                SPWeb web = SPContext.Current.Web;
                foreach (SPList list in web.Lists)
                    lists.Add(list); 

                HttpRuntime.Cache.Add("SimpleSampleCache",
                lists,
                null,
                DateTime.MaxValue,
                TimeSpan.FromMinutes(10),
                System.Web.Caching.CacheItemPriority.Default, null);
            }
            else
            {
                status = "The following items <strong>ARE</strong> fetched from the cache!<br/><br/>";
                lists = (List<SPList>)HttpRuntime.Cache["SimpleSampleCache"];
            } 

            writer.Write(status);
            foreach (SPList l in lists)
                writer.WriteLine(l.Title + " - " + l.ItemCount + " items<br/>");
        } 
    }
}

Summary & Download!

I always use the HttpRuntime or HttpContext objects to store and read my cached objects. You can of course use the built-in caching functionality of WSS 3.0 Web Parts if you feel that you have the need for it. However this approach works everytime, everywhere. Not just for Web Parts of course, but for any kind of ASP.NET hooked application.

You can download the sample project [here]

Thanks for tuning in,
Cheers


Published: Oct-07-08 | 11 Comments | 0 Links to this post

SharePoint .NET 3.5 auto-configuration – escape the manual overhead!

I have previously talked about how you manually can configure your SharePoint environment to enable .NET 3.5. My approach were to always do this manually, but it seems that there’s a sweet feature for this purpose created, automating this process.

As a tip from Jeremy Thake, I’m posting the link to a CodePlex project called “Features” which obviously have a feature that deals with configuring your web application without any manual steps like modifying xml snippets in web.config.

Even though the manual steps I’ve provided in my blogpost only takes about 1-2 minutes to perform, this approach eliminates the human facor – which often is the cause to a lot of headaches!

Thanks for the tip Jeremy, and hope everyone else will find this interesting aswell!

More on .NET 3.5 to come later.


Published: Sep-30-08 | 6 Comments | 0 Links to this post

How to: LINQ with SharePoint - .NET 3.5 Framework with SharePoint Part 2

Author: Tobias Zimmergren
Blog: http://www.zimmergren.net

Introduction

In my previous article title "How to: Get up and running with .NET 3.5 in your SharePoint environment" I talked about how you can manually set up your SharePoint environment for use with Microsoft .NET Framework 3.5.

In this article I will talk about how you can incorporade some of the technologies used in .NET 3.5 to query a SharePoint list. More precisely, I will talk about how you easily can use LINQ from the .NET 3.5 framework to get started with .NET 3.5 in SharePoint.

A more in-depth article might be posted later, but this one is simply providing simple code instructions to what a Web Part that utilizes LINQ can look like!

Prerequisites

In order to follow along with this walkthrough, you should have the following bulletpoints checked:

Creating a custom Web Part which utilizes .NET 3.5 in SharePoint

The code below will give you the heads up on how to fetch the SPListItem objects from an SPList object and sort them alphabetically. You can of course use the 'where'-clause with LINQ aswell to filter out which objects (SPListItem objects) to fetch from the SPList.

Example task list to fetch the data from:
image

Using the following code, I've used LINQ to retreive all the list items and sort them ascending by title!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;

namespace Zimmergren.net35.LINQWebPartSample
{
    public class SPLINQ : System.Web.UI.WebControls.WebParts.WebPart
    {
        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            base.Render(writer);
            SPList taskList = SPContext.Current.Web.Lists["Tasks"]; 

            // Get items, order by title alphabetically and assign to taskListItems
            var taskListItems = from SPListItem tItem in taskList.Items
                                orderby tItem.Title
                                ascending select tItem;
 

            foreach (SPListItem taskItem in taskListItems)
                writer.WriteLine(taskItem.Title + "<br/>\n");
        }
    }
}

The bold text in the above code block is the LINQ statement to fetch all items in the SPList and order them ascending by Title. You can of course make much more complex queries using LINQ in order to fetch other objects based on different criteria.

This will produce a simple output like this, sorting the items alphabetically:
image

Summary and Download

This was a very (very) basic and simple example of how you can use any .NET 3.5 technology to get started with some new cool stuff.

I utilized a basic LINQ expression in this article which of course can be heavily modified if you want to retreive other things from your list(s). Perhaps a future article will take on some more advanced LINQ expressions in conjunction with SharePoint?! :-)

Anyway, you can download the sample project from here: Zimmergren.net35.LINQWebPart.zip

Thanks for tuning in and please leave a comment

As always, there's plenty of readers but few people showing their appreciation through the comments - please leave a comment :)

Hope it helps :-)


Published: Sep-28-08 | 15 Comments | 0 Links to this post

How to: Get up and running with .NET 3.5 in your SharePoint environment

Since I've been a bit on the lazy side when it comes to the blog (due to multiple reasons..), I'm thinking about writing up an article-series where I'll talk about .NET 3.5 and what it has to offer when used in conjunction with SharePoint. Any input is welcome, of course :)

Introduction

In this article I will try to get you up and running with the .NET 3.5 framework in your SharePoint environment, just like I've previously described how you can get AJAX and Silverlight 2.0 up and running:

I will now let .NET 3.5 be a part of some of my upcoming SharePoint projects, and because of that I thought it could be a good thing to blog about it if there's anyone out there looking to do the same!

Prerequisites before we get started

In order to follow along, I assume the following few bulletpoints are in place:

  • Microsoft .NET 3.5 Framework is installed on the front-end server
  • You already have got a Web Application on which you want to do these changes

Add support for .NET 3.5 in SharePoint (WSS 3.0 or MOSS 2007 alike)

Here you will find a manual step by step instruction on what web.config values to set in order for .NET 3.5 to work properly with your SharePoint installation.

Note: I've added some linebreaks in order for the text to show up properly in my blog, you may remove them if you want your web.config to be pretty ;)

Note2: All additions to any elements in the web.config file should be added at the bottom/end of each element unless excplicitly stated otherwise.

1) Add the following snippet inside the <configSections> element

<sectionGroup name="system.web.extensions"
                type="System.Web.Configuration.SystemWebExtensionsSectionGroup,
                System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                PublicKeyToken=31BF3856AD364E35">
    <sectionGroup name="scripting"
                type="System.Web.Configuration.ScriptingSectionGroup,
                System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                PublicKeyToken=31BF3856AD364E35">
       <section name="scriptResourceHandler"
                type="System.Web.Configuration.ScriptingScriptResourceHandlerSection,
                System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                PublicKeyToken=31BF3856AD364E35" requirePermission="false"
                allowDefinition="MachineToApplication"/>
       <sectionGroup name="webServices"
                    type="System.Web.Configuration.ScriptingWebServicesSectionGroup,
                    System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                    PublicKeyToken=31BF3856AD364E35">
        <section name="jsonSerialization"
                type="System.Web.Configuration.ScriptingJsonSerializationSection,
                System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                PublicKeyToken=31BF3856AD364E35" requirePermission="false"
                allowDefinition="Everywhere" />
        <section name="profileService"
                type="System.Web.Configuration.ScriptingProfileServiceSection,
                System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                PublicKeyToken=31BF3856AD364E35" requirePermission="false"
                allowDefinition="MachineToApplication" />
        <section name="authenticationService"
                type="System.Web.Configuration.ScriptingAuthenticationServiceSection,
                System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                PublicKeyToken=31BF3856AD364E35" requirePermission="false"
                allowDefinition="MachineToApplication" />
        <section name="roleService"   
                type="System.Web.Configuration.ScriptingRoleServiceSection,
                System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
                PublicKeyToken=31BF3856AD364E35" requirePermission="false"
                allowDefinition="MachineToApplication" />
      </sectionGroup>
    </sectionGroup>
  </sectionGroup>

2) Add the following snippet inside the <pages> element

<controls>
  <add tagPrefix="asp" namespace="System.Web.UI"
        assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
        PublicKeyToken=31BF3856AD364E35"/>
  <add tagPrefix="asp" namespace="System.Web.UI.WebControls"
        assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
        PublicKeyToken=31BF3856AD364E35"/>
</controls>

3) Add the following snippet inside the <assemblies> element

<add assembly="System.Core,
    Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Extensions,
    Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Data.DataSetExtensions,
    Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Xml.Linq,
    Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=B77A5C561934E089"/>

4) Add the following snippet inside the <httpHandlers> element

<add verb="*" path="*.asmx" validate="false"
    type="System.Web.Script.Services.ScriptHandlerFactory,
    System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=31BF3856AD364E35"/>
<add verb="*" path="*_AppService.axd" validate="false"
    type="System.Web.Script.Services.ScriptHandlerFactory,
    System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=31BF3856AD364E35"/>
<add verb="GET,HEAD" path="ScriptResource.axd"
    type="System.Web.Handlers.ScriptResourceHandler,
    System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=31BF3856AD364E35" validate="false"/>

5) Add the following snippet inside the <httpModules> element

<add name="ScriptModule"
    type="System.Web.Handlers.ScriptModule,
    System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
    PublicKeyToken=31BF3856AD364E35"/>

6) Add the following snippet inside the <SafeControls> element

<SafeControl Assembly="System.Web.Silverlight,
            Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            Namespace="System.Web.UI.SilverlightControls" TypeName="*" Safe="True" />
<SafeControl Assembly="System.Web.Extensions,
            Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            Namespace="System.Web.UI" TypeName="*" Safe="True" />

7) Add the following snippet inside the <configuration> element

    <system.web.extensions>
      <scripting>
        <webServices>
        </webServices>
      </scripting>
    </system.web.extensions>
    <system.webServer>
      <validation validateIntegratedModeConfiguration="false"/>
      <modules>
        <add name="ScriptModule" preCondition="integratedMode"
            type="System.Web.Handlers.ScriptModule,
            System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
            PublicKeyToken=31bf3856ad364e35"/>
      </modules>
      <handlers>
        <remove name="WebServiceHandlerFactory-Integrated" />
        <add name="ScriptHandlerFactory" verb="*"
            path="*.asmx" preCondition="integratedMode"
            type="System.Web.Script.Services.ScriptHandlerFactory,
            System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
            PublicKeyToken=31bf3856ad364e35"/>
        <add name="ScriptHandlerFactoryAppServices" verb="*"
            path="*_AppService.axd" preCondition="integratedMode"
            type="System.Web.Script.Services.ScriptHandlerFactory,
            System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
            PublicKeyToken=31bf3856ad364e35"/>
        <add name="ScriptResource" preCondition="integratedMode"
            verb="GET,HEAD" path="ScriptResource.axd"
            type="System.Web.Handlers.ScriptResourceHandler,
            System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
            PublicKeyToken=31bf3856ad364e35" />
      </handlers>
    </system.webServer> 
    <system.webServer>
       <validation validateIntegratedModeConfiguration="false"/>
       <modules>
         <remove name="ScriptModule" />
         <add name="ScriptModule" preCondition="managedHandler"
            type="System.Web.Handlers.ScriptModule,
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
            PublicKeyToken=31BF3856AD364E35"/>
       </modules>
       <handlers>
         <remove name="WebServiceHandlerFactory-Integrated"/>
         <remove name="ScriptHandlerFactory" />
         <remove name="ScriptHandlerFactoryAppServices" />
         <remove name="ScriptResource" />
         <add name="ScriptHandlerFactory" verb="*" path="*.asmx"
            preCondition="integratedMode"
            type="System.Web.Script.Services.ScriptHandlerFactory,
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
            PublicKeyToken=31BF3856AD364E35"/>
         <add name="ScriptHandlerFactoryAppServices" verb="*"
            path="*_AppService.axd"
            preCondition="integratedMode"
            type="System.Web.Script.Services.ScriptHandlerFactory,
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
            PublicKeyToken=31BF3856AD364E35"/>
         <add name="ScriptResource" preCondition="integratedMode"
            verb="GET,HEAD" path="ScriptResource.axd"
            type="System.Web.Handlers.ScriptResourceHandler,
            System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
            PublicKeyToken=31BF3856AD364E35" />
       </handlers>
    </system.webServer>

8) You're done

When you've added the needed tags, you're all set - you can now run your .NET 3.5 applications inside SharePoint (of course, this applies to the web application where you just added these settings.

To see that your site still works, do the following:

  • IISRESET
  • Launch your site where you've made the changes!
  • Cross your fingers

Cool, what's next?

Well, if you've managed to get your site up and running - you can now create webparts, features, controls or whatever you'd like to create and have them published to your site.

This article describes how you do these things manually, but what if you want to do these things automatically somehow? Is that possible?
- Yes, but that's going to be covered in an upcoming blogpost

Please leave some comments

As you might know, I like to get feedback and usually answers all mails/comments when I've got the time. Please leave any feedback, suggestions or opinions in the comments below or mail me/use the MSN gadget.

Thanks for tuning in, now I'm feeling the blog-flow again - cheers


Published: Sep-22-08 | 27 Comments | 0 Links to this post

U2U CAML Query Builder - New version out

I just read Karine Bosch's blog where she posted some news on the U2U CAML Query Builder, so I just ought to get your attention in that direction.

Check the detailed updates out in Karine's blog:
http://www.u2u.info/Blogs/karine/Lists/Posts/Post.aspx?List=d35935e0%2D8c0e%2D4176%2Da7e8%2D2ee90b3c8e5a&ID=30

Cheers


Published: Jul-26-08 | 2 Comments | 0 Links to this post

Infrastructure updates for MOSS 2007 and WSS 3.0

As some of you might already know, Microsoft released their infrastructure updates to MOSS and WSS yesterday (2008-07-15).

Instead of yabbing along here about the actual updates, I'm simply going to provide you with links to the downloads and documents, so you can read it yourself.

Sidenote: Just installed the update for WSS 3.0 on my blog, running WSS 3.0 SP1 - and so far so good.

32-bit downloads

Download 32-bit: Infrastructure Update for Windows SharePoint Services 3.0 (KB951695)
Download 32-bit: Infrastructure Update for Microsoft Office Servers (KB951297)

64-bit downloads

Download 64-bit: Infrastructure Update for Windows SharePoint Services 3.0 (KB951695)
Download 64-bit: Infrastructure Update for Microsoft Office Servers (KB951297)

Information about the updates

Documentation: Infrastructure Update for Windows SharePoint Services 3.0
Documentation: Infrastructure Update for Microsoft Office Servers

Get going :)


Published: Jul-16-08 | 3 Comments | 0 Links to this post

SharePoint's hidden user-list - User Information List

Okay, this might not come as news to most SharePoint developers who've been around a while, but lately I've been messing with the User Information List in SharePoint and it doesn't seem that many people know that it exists.

Note: This list is only visible to and accessible by administrators.

User Information List - Background

The User Information List stores information about a user by having some metadata set up for the user. Some examples are Picture, Email, DisplayName, LoginName etc. ) For a complete list of fields, see further down this blogpost under "User Information List Fields".

Something to note is that when a user is granted access to a site, a new item will be created in the User Information List storing some information about the user.

When a user add/create or edit an item, SharePoint will display something like "Last modified at 1/1/2008 by Tobias Zimmergren" like the following pic:

image

In this example the DisplayName (used to display System Account) is gathered from the User Information List

Browsing the User Information List

The User Information List can be accessed (Only if you're admin) via the browser by navigating to /_catalogs/users/simple.aspx from your site. (Ex: http://zimmergren/_catalogs/users/simple.aspx)

This works for both Windows SharePoint Services 3.0 (WSS 3.0) and Microsoft Office SharePoint Server 2007 (MOSS 2007) and looks like this when you access it through the browser:

image

Write code to interact with the User Information List

If you want to interact with this list to set properties on a user (Probably only want to do this if you're running WSS) you could do it like this:

// Instantiates the User Information List
SPList userInformationList = SPContext.Current.Web.SiteUserInfoList;

// Get the current user
SPUser user = SPContext.Current.Web.EnsureUser(@"ZIMMER\TobiasZimmergren");

// The actual User Information is within this SPListItem
SPListItem userItem = userInformationList.Items.GetItemById(user.ID);

The above code will give you the SPListItem object which links to the currently logged in user (the one executing the request).

You can then work with the SPListItem object like normal to get or set the properties like this:

string pictureURL = userItem["Picture"].ToString();

User Information List Fields

Instead of writing out all the fields/columns availible, you can simply create a new Console Application and insert the following code in order to output all the fields names and internalnames:

image
Note: You will ofcourse have to change the URL and User LoginName
Note2: No comments needed about not disposing the objects as this was merely a sample, eh? ;)

You're welcome

Hope this will enlighten some of you people in your quest for the holy grail (SharePoint All-Mighty Knowledge?)

Work is calling me, so I'll have to end this small post right here and right now, catch you soon again.


Published: Jun-25-08 | 42 Comments | 0 Links to this post
 Next >>