SharePoint Tools for Windows Azure, Visual Studio, jQuery, and HTML5

As I mentioned in my last post, at the recent SharePoint 2011 conference, I attended a number of sessions where Visual Studio played a major role. Andrew Connell articulated design patterns around using SharePoint with Windows Azure, Ted Pattison showed patterns around jQuery, HTML5 and oData, and Eric Shupps used the performance testing tools in VS2010 to show the impact of performance tweaks.

In all of the sessions mentioned above, reference was made to add ins, extensions, or other tools that make working with SharePoint and Azure a great deal easier. I took note of most of them, and in the process of summarizing them, thought that I should amalgamate them with my own current list of dev tools, and post it here. Extensions can and should be installed via the extensions manager in Visual Studio, and I’ll note them below.

Cloudberry Utility for working with Azure BLOB Storage. Makes moving files to/from blob storage simple
Visual Studio 2010 SharePoint Power Tools* Adds a sandboxed Visual Web Part item template and other enhancements.
CKS Development Tools for SharePoint* Community led effort that includes many Tools and templates for SharePoint development
CAML Intellisense for VS2010* Adds Intellisense to VS2010 for those of use still stuck with CAML
Visual Studio 2010 Silverlight Web Part* Project Template for writing Silverlight web parts – both full trust and sandboxed supported
Web Standards Update for Visual Studio 2010 SP1* Adds Intellisense for HTML5 and CSS3 to VS2010
SharePoint Timer Job Item* Supports the creation of administrative timer jobs in SharePoint 2010
SharePoint 2010 and Windows Azure Training Course Training course to get up to speed on working with SharePoint 2010 and Windows Azure
jQuery Libraries Main libraries for working with jQuery
jQuery UI Library  UI controls for use with jQuery
jQuery Templates Add in for the templating of controls in jQuery
Modernizr Open source project to allow older browsers to work with HTML5/CSS3 elements

 

*Available through the Visual Studio Extension Manager

Building an Automatic XML Sitemap Generator for your SharePoint Site

Although SharePoint 2010 provides a top notch environment for building corporate web sites, one of the things that it does not do is to generate an XML sitemap file automatically. This is unfortunate, as this type of file is used by the major search engines to help discover content on your site. Luckily, the development tools for SharePoint make this process relatively straightforward. Below, I’ll walk through the process of creating a branded event receiver to rebuild the site map whenever a page is approved.

In order to follow along, you’ll need a copy of Visual Studio 2010 installed on a machine that also has SharePoint Server installed (SharePoint Foundation won’t cut it for this one – we’re using the publishing features). You’ll also need the Visual Studio Tools for SharePoint installed.

If you don’t want to walk through the whole creation process, and just want a site map builder, you can download the solution file from codeplex here. Just note that your web application will need an internet zone for this to work properly.

1. Create an Event Receiver Project

Open Visual Studio and create a new project. Select the SharePoint node, and the Event Receiver project template. Give the Solution and the Project a name, then click OK.

image

The project name will be the name of the SharePoint solution. It can be changed later, but it’s much easier to get it right ahead of time. The next prompt will ask for the debugging site, and whether this is a farm, or a sandbox solution. The debugging site will need to have the publishing features enabled (this can be done later, and the debugging site can be changed through the Project Properties). Select a farm solution and click Next.

The next screen will ask what type of event receiver that you want to build. The available options are a function of what is available in your debugging site (chosen previously). For example, the Pages library will not be an option for the event source if the Publishing infrastructure has not been enabled. For our purposes, we want this to un whenever a page in the Pages library has been updated. Therefore we select the type to be List Item Events, the source to be a Pages library, and the event to be “An item was updated”.

image

Click Finish when done. The system will create a feature and an event receiver for you.

2. Make Any Branding and Name Changes

This is not absolutely necessary, but the first thing that I like to do is to change my assembly name and my root namespace to distinguish the work done by my organization from any other things installed. To do this, you open the project properties page, click the Application tab, and change them there.

image

The Assembly Name controls the file name of the DLL that is generated, and the root namespace controls where your classes are found in the .Net Framework. Unfortunately changing the root namespace does not update the assembly references in the project, and if you attempt to debug the project at this point, you will receive this oh so helpful error:

“Error occurred in deployment step ‘Activate Features’: Operation is not valid due to the current state of the object.”

What you need to do is to update all references to the old namespace in the project. Specifically, the Elements.xml file in the event receiver folder needs the correct starting namespace. Open the file for editing and replace the old assembly name with your new one.

image

Save the file, and close it if you wish,but we will be coming back to it.

Next, we want to name our feature. The feature will have an internal name that is used when it is referred to programmatically (through powershell, sysadm, etc) and a display name (title), that will be used in the UI. First we’ll modify the internal name. The easiest way to do this is to open the Features folder, and rename the Feature1 node. We’ll call our feature xmlSiteMapBuilder.

The tools are smart about renaming everything in the features folder. Next, double click on the feature node (in our case, xmlSiteMapBuilder). This opens the feature designer. All that we need to do here is to change the title, the description and the scope. The first two are cosmetic (but important!). However, we want our event receiver to run on all pages in the site collection, so we need to change its scope from Web to Site.

image

At this point, it’s a good idea to run the project to make sure that everything is OK. One you’ve done so, and the browser window opens, go to Site Actions-Site Settings, and select Site Collection Features. You should see your feature there, in an activated state, with your title and description.

image

Next, we want to change the name of our event receiver to something other than “EventReceiver1”. click on the EventReciver1 folder and rename it, in our case to PageChangedEventReceiver. Then, rename your EventReceiver1 class in a similar fashion. You will be prompted to update all references to the class when you do this, so select yes. Unfortunately, the updates don’t completely affect our pesky Elements.xml file, and we need to perform these manually. Open this file and change all references to the old name to use the new one.

image

Now we’re ready to write some code!

3. Add the Logic

You can add all of your code directly into your event receiver class. However in our case, we need to perform the same functions not only when the event fires, but also when the feature is activated. Therefore, we add a new class to the project, simply called Builder. In addition, we will need to access the Microsoft.SharePoint.Publishing namespace, so we need to add a reference to it to our project.

Without going through it line by line, our code will walk through our site collection, find all of the pages, check to see if they have been published and then build a site map entry for each one, using the URL prefix for the Internet zone. The complete code is available on the Codeplex site mentioned above, but the content of the Builder class is below.

Imports System.Text

Imports Microsoft.SharePoint.Publishing

Imports System.IO

Imports Microsoft.SharePoint.Administration

 

Public Class BuilderMain

    Private _siteURL As String

    Private _SiteID As Guid

 

    Dim textWriter As StringBuilder = Nothing

    Dim dateFormatString As String = "yyyy'-'MM'-'dd"

   

    Public Sub New(ByVal siteID As Guid)

        _SiteID = siteID

    End Sub

    Public Sub New(ByVal Url As String)

        Dim st As New SPSite(Url)

 

        _SiteID = st.ID

    End Sub

 

    Public Sub Run()

        Try

            textWriter = New StringBuilder(String.Empty)

         

            Dim site As SPSite = New SPSite(_SiteID, SPUrlZone.Internet)

            With site

                Dim web As SPWeb = site.RootWeb

                With web

                    textWriter.AppendLine("<?xml version=""1.0"" encoding=""UTF-8""?>")

                    textWriter.AppendLine("<urlset xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"" xmlns=""http://www.sitemaps.org/schemas/sitemap/0.9"">")

                    LoadTreeViewForSubWebs(web) ' kick it off with the root web As 

                    textWriter.AppendLine("</urlset>")

                    Dim stream As MemoryStream = New MemoryStream(Encoding.UTF8.GetBytes(textWriter.ToString()))

                    web.Files.Add("sitemap.xml", stream, True)

                    stream.Close()

                End With

            End With

 

        Catch ex As Exception

            errorHandler(ex, "BuildSitemap")

        End Try

    End Sub

 

    Private Sub LoadTreeViewForSubWebs(ByVal currentWeb As SPWeb)

        Dim pPageCol As PublishingPageCollection = Nothing

        Dim tagLabel As String = String.Empty

        If PublishingWeb.IsPublishingWeb(currentWeb) Then

            Dim pWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(currentWeb)

            pPageCol = pWeb.GetPublishingPages()

        End If

        'create xml link to site

        'to remove the link to the site (without a page), remove the next line

        writeSitemapNode(currentWeb.Url + "/", currentWeb.LastItemModifiedDate.ToString(dateFormatString))

 

        'create xml links to site pages

        If Not pPageCol Is Nothing Then

            LoadTreeViewForSubWebPages(pPageCol)

            pPageCol = Nothing

        End If

        For Each web As SPWeb In currentWeb.Webs

            Dim _file As SPFile = web.GetFile(web.Url.ToString() + "nopost.xml")

            If Not _file.Exists Then

                LoadTreeViewForSubWebs(web)

            End If

        Next

        currentWeb.Close()

 

    End Sub

 

    Private Sub LoadTreeViewForSubWebPages(ByVal currentPages As PublishingPageCollection)

        Dim page As PublishingPage

        For Each page In currentPages

            If page.Url.EndsWith("aspx") Then

                If page.ListItem.HasPublishedVersion Then

                    writeSitemapNode(page.PublishingWeb.Url + "/" + page.Url, page.LastModifiedDate.ToString(dateFormatString))

                End If

 

            End If

        Next

    End Sub

 

    Private Sub writeSitemapNode(ByVal pageLocation As String, ByVal lastModified As String)

        textWriter.AppendLine(vbTab + "<url>")

        'replace secured links with non-secured links

        textWriter.AppendLine(vbTab + vbTab + "<loc>" + pageLocation.Replace("https:", "http:") + "</loc>")

        textWriter.AppendLine(vbTab + vbTab + "<lastmod>" + lastModified + "</lastmod>")

        textWriter.AppendLine(vbTab + "</url>")

    End Sub

 

 

    Private Sub errorHandler(ByVal errorMessage As Exception, ByVal errorLocation As String)

 

        Try

            Dim _eventLog As System.Diagnostics.EventLog = New System.Diagnostics.EventLog("Timer Jobs")

            _eventLog.Source = "Sitemap Generator"

            _eventLog.WriteEntry("Error (" + errorLocation.ToString() + "): " + errorMessage.Message.ToString())

            _eventLog.Close()

            _eventLog = Nothing

        Catch

 

        End Try

    End Sub

End Class

 

Next, we need to call our builder from our event receiver. Our code will go into the ItemUpdated sub. The builder constructor takes either a URL or a Site ID as an argument, and since the item can be obtained through the properties object, our job is pretty straightforward. All we need to do is to check to see if the item has been approved.

Public Overrides Sub ItemUpdated(ByVal properties As SPItemEventProperties) 

   MyBase.ItemUpdated(properties)

   If properties.ListItem.ModerationInformation.Status = SPModerationStatusType.Approved Then

        Dim smb As New BuilderMain(properties.SiteId)

        smb.Run()    

    End If

End Sub

 

4. Add a Feature Receiver

Of course, we don’t want to wait until a page is edited, we want to build a site map as soon as the feature is activated. To do that, we need to add a feature event receiver. To do this, we simply right click on our feature node (in this case, xmlSiteMapBuilder) and select Add Event Receiver. The designer will open the new class, and the 4 event receivers will be commented out. Simply uncomment the FeatureActivated Sub, and add the required code.

Public Overrides Sub FeatureActivated(ByVal properties As SPFeatureReceiverProperties)

    Dim Parent As SPSite = CType(properties.Feature.Parent, SPSite)

    Dim smb As New BuilderMain(Parent.ID)

    smb.Run()

End Sub

 

We don’t need to clean anything up when the feature is deactivated, so this is the only code that we need to add. Go ahead and run the project, and you should find a brand new sitemap.xml file in the root of your site collection. You can use SharePoint Designer to see it, or just use the browser with a url of http://yoursitecollectionurl/sitemap.xml

That’s all there is to it. A little bit of code, and you’re well on your way to Search Engine Optimization.

How to Build a Site Collection Template from A Web Template in SharePoint 2010

First off, I should state that there’s really no such thing as a site collection template. What happens when a new site collection is created is that the collection gets created, and then a web template is applied to the root site. This whole process is actually decoupled in SharePoint 2010, and you no longer need to select a template when the site collection is created (as documented previously by Todd Klindt). Todd has a very clever solution to getting your web template to be used at the root site, but I recently had a requirement to have it fully automated, and to be visible to the templates available when creating a site collection in Central admin.

This was relatively straightforward in SharePoint 2007, you would save a particular site as a template, then go to the template gallery, download it to the file system on a front end server, and then run an STSADM command to have it added to the Site definitions list. However, in SharePoint 2010, site templates are no longer .STP files,they use .WSP solutions in the user solution gallery. That should be easy,right? Just save off the  WSP file, add the solution to the farm with either PowerShell or STSADM. The solution will actually install, but your site template won’t show up. The main reason is that the actual web template is scoped to “web” and for it to show up for site collections, it needs to be scoped for the farm.

The good news is that you can import a WSP file directly into Visual Studio 2010, edit it, and create a new solution that does work. I will now attempt to describe the relevant steps, and a few gotchas to do this.

1. Save The Site as a Template

Once you have your site looking and behaving the way that you want, it’s time to save it off.  Select Site Settings, and click Save Site As Template – It’s under the Site Actions section. Give the template a file name, name, and if desired, a description. Once you select OK, the solution will be created and saved to the solution gallery, which is at the root of the site collection. You’ll want to go there next, and you can do so by clicking on the “solution gallery” link in the successful save confirmation page, or by navigating to the root of the site collection, then selecting Site Actions – Site Settings and clicking on the Solutions Gallery link. There is no more Site Template Gallery!!!

image

2. Save the WSP File Locally

From the solutions gallery, Click the name of your solution, and you will be prompted to save the wsp file. Go ahead and do that, and then you need to delete the template from the gallery. Why? You’ll be ultimately registering it in the farm, and you don’t need any confusion as to which template to choose. As well, if you’ll be using the same name, this will lead to conflicts, so it’s best to eliminate it altogether.

3. Create a Project in Visual Studio

Open Visual Studio and create a new project. Make sure that you have the SharePoint 2010 Templates showing, and then select the “Import SharePoint Solution Package” template.

image

From the next screen select “Deploy As a Farm Solution”, and click Next.

image

Next, click Browse and navigate to the WSP file downloaded in 2.

image

Finally, ensure that all of the included items are selected, and select Finish.

image

Visual Studio will then import all of the items into the project. Now we’re ready to modify the project.

4. Modify The Feature Definitions

There will typically be 4 Features created for a site template, aptly named Feature1 through Feature 4. Personally, I like my feature names to be a little more descriptive than that. Feature 1 is for List Instances, Feature 2 is for Modules, Feature 3 is for the template itself, and Feature 4 is for the PropertyBag.

The purpose of our solution is to make the site template available, and the other features are effectively there in a supporting role. Currently, all 4 features are scoped to web, and all 4 are visible. In addition to renaming them, we want to hide features 1,2, and 4 from display, and we want to scope feature 3 to the farm. 

First, we’ll modify the Feature name. Simply Single Click (or right click and rename) on the Feature in the Visual Studio Solution Explorer, and enter a new name. You’ll notice that all of the supporting elements below are automatically renamed as well.

image

Next, We’ll want to modify the Title of the features. The title is what is used when the feature is displayed in the feature list. Although we’ll be hiding 3 of them, it’s still a good idea to use a descriptive title. Double click on the feature, and the Feature Definition box will open in the main window. Modify the Title, and if desired the Description field to something meaningful to your users.

Go ahead and repeat this step for all of the 4 features

With the feature definition in the main window, the feature properties should be loaded in the properties toolbox (if you don’t have it open, open it). We want to set the Is Hidden property to true for all of the features except for the Web Template feature itself (Feature 3).

image

The web template feature itself requires an additional modification, we need to change the scope from site to farm. We can do this in either the properties window or the feature definition window, but the feature definition window is a little more obvious.

image

5. Modify the Template Definition Itself.

This step may not be required if the template name and title will be identical to that which was saved initially. However, in this case, we have called the solution Sample 1, and when the template was saved, it was MyCustomSite. We need to modify the template itself to be called Sample 1, and we may have some additional tweaks.

From the Solution Explorer, open the Web Templates Folder and change the name of the Template by single, or right clicking on it. The feature definitions will be updated automatically.

image

Next, we need to open the Elements.xml file, and change the Name and the Title tag to the new name. Search and replace is a good idea here. Next, open the ONet.xml and change the Title attribute in the Project tag to an appropriate value, in this case, Sample 1.  This file can also be used to remove any feature dependencies that may not exist in the destination farm, but be careful – other elements of your template may be reliant on them.

6. Test the Project

Click on the Debug start button in Visual Studio and your template will be deployed to the server, and you’ll be prompted to create a new subsite. If you see your template in the custom tab, all is well. Go ahead and create a test site to make sure that everything is working. Visual studio may prompt you with deployment conflicts, just let it go ahead and resolve them automatically.

7. Deploy the Solution

We are now ready to deploy the solution to the farm. First, set Visual Studio to Release mode from the toolbar:

image

Then, Right Click on the project, and select Package

image

Then, you’ll need to navigate to your Visual Studio project folder, and then into the BINRelease folder. There you will find a .WSP file with the name of your project. You can either work with the file in place, or copy it to a folder, but next we will add the project to the Farm solution gallery. To do this, we will either use STSADM (old school) or PowerShell (the cool new way). I’m old, so I still use STSADM for solutions, but I’ll show both.

To add the solution using stsadm.exe, open up a command prompt (in administrator mode if UAC is turned on), and navigate to the folder containing the solution file. The syntax is:

C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14BINstsadm.exe –o addsolution –filename sample1.wsp

Where sample1.wsp is the name of your solution file.

To use PowerShell, open the SharePoint 2010 Management Shell, and enter:

add-SPsolution –LiteralPath c:solutionssample1.wsp

The argument for LiteralPath is the complete path to the solution file. If there are and spaces in the path name, it needs to be encased in quotes.

8. Deploy the Solution

Now that the solution has been added, it needs to be deployed. To do so, start central admin, Go to System Settings, and select Manage farm solutions in the Farm Management Section:

image

Click on your solution name, and then click the Deploy Solution button. Click the OK button on the following screen, and your solution will be deployed.

You can control whether or not the template is available by turning off the farm feature. You can do that from central admin by navigating to System Settings – Manage Farm Features. From here, you can turn your template on and off.

image

9. Create New Site Collection

At this point, we should be good to go. From Central Administration, navigate to Application Management, and click Create Site Collections. On the create screen, give the new collection a title, and a URL. Then, in the Template Selection, click the Custom tab, and your template should appear there.

image
 

Give it a site collection administrator, and click OK. After a few moments, the site will be created, and you can navigate to it.

image

Simple, right?

Well, Microsoft giveth and Microsoft taketh away. Adding the template to the farm is considerably more involved with 2010 than with 2007. However this approach is also a great deal more flexible – you can tweak that template to your heart’s content, and if you have ever tried to create a site template with 2007 using Visual Studio, you can really appreciate how Visual Studio 2010 makes it significantly easier.

Configuring and Branding a Visual Web Part Solution for SharePoint 2010 With Visual Studio 2010

Although I originally saw the new Visual Studio Tools for SharePoint 2010 back in August 2009, this past week was the first opportunity that I was able to get down to business with them, working with a web part solution (I don’t get to develop as much as I’d like to these days…). The beauty of these tools is that they not only (finally) give you a true “F5” approach to developing SharePoint applications, but they also build out and deploy web part solutions automatically for you. Indeed, every run of your application goes through the packaging and deployment process.

Before I get into this, I want to say that to a jaded old SharePoint developer, these tools are like manna from heaven. Not only is ease of use greatly improved, but so is speed of deployment and debugging.

However, unless you want your feature to be named “Feature1” and your solution to be named “MySolution”, and you want your assembly to be named exactly the same as your project, you’ll want to brand your solution a bit. Renaming a project and/or a component file will do a certain amount of refactoring automatically for you, but it isn’t complete and there are a few gotchas. I thought that I’d outline a few of them,and walk you through a branding process. This example uses a Visual Basic project,and there will be differences with C#, but the concepts remain the same.

1. Create your Visual Web Part, and give it a name. In this case, the name will be “Hello World” (Original, huh?)

image

2. Next, change the Web part names from “VisualWebPart1” to your name, in this case “HelloWorld” (notice the lack of spaces). When asked to perform a rename of all references, select yes. Don’t get too excited, it only changes code references.

image

3. Then, do a search and replace (Ctl-H) on the entire solution, and replace “VisualWebPart1” with your name – in our case “HelloWorld”

image

It should find and replace 5 references (for a VB.NET project at least).

4. If you want to change the name of your assembly and/or root namespace, go to project properties and do so. In our case, the Assembly name will be changed from “Hello World” to “SecondFoundation.HelloWorld”, and the root namespace will be changed from “Hello_World” to “SecondFoundation.HelloWorld”.

image

5. Next, edit the SharePointProjectItem.spdata file. This is a hidden file and you’ll need to turn on the “Show All Files” option in the solution explorer. This file controls the auto generation of several project components.

image

In the SafeControl entry, you’ll find that the Namespace attribute reflects the original name of the assembly. You’ll need to update it to reflect your change:

image

6. Next, edit your xxxx.webpart file (in our case HelloWorld.webpart). You’ll need to change the name attribute of the type entry in the <metaData> section to reflect your changes. While you’re at it, you should likely change the Title and Description properties to something meaningful, although this isn’t required.

image

7. You’ll need to edit your xxxxxxUserControl.ascx file (in our Case HelloWorldUserControl.ascx) and change the Inherits attribute from the Control entry (the last line) to reflect the namespace changes.

image

8. Optionally, edit the Elements.xml file, and change the Group property to something meaningful.

image

9. Open up the Features section in the Solution Explorer, and change the name from Feature1 to something meaningful. In our case, to continue on with my highly creative theme, we’ll call it HelloWorld.

image

10. Finally, Edit your .ascx file and add some content to allow us to see the web part on the page. I’ll leave it to you to guess what content I’m adding…..

Run your project, and add your new web part to the page that pops up. All should be well.

image

This should get you going with creating non-generic web parts. Enjoy.