Tuesday, December 27, 2011

Property Bags in SharePoint 2010

What's a Property Bag?

Many SharePoint objects such as Web applications, site collections, web and lists have a property bag associated with them.  What are these things?

The property bag is a key-value dictionary that stores configuration information.  For example, the property bag for a SharePoint Wiki page stores the HTML on the page.

What Good Are They?

A property bag can be used by a SharePoint developer to store configuration information.  It seems best suited to information that doesn't change often and might be a really good alternative to the SharePoint web.config file.

Reading a Property (2010)

Access to the property bag should be dead simple, but there are compatibility issues. For 2010, you should use the case-sensitive "GetProperty" method.  For 2007, you use the all-lower-case Properties collection. The latter will not be able to access 2010 case-sensitive properties:

using (SPSite siteCollection = new SPSite(http://localhost/)
{
    using (SPWeb myWeb = siteCollection.RootWeb)
    {
        lblValueFound.Text = myWeb.GetProperty("mike").ToString();
    }
}

Adding a Property (2010)

Most of the samples I found on the web are SharePoint 2007 and I can't get them to work in 2010. Most of these samples look something like this:

// Doesn't work in 2010.  The property is not persisted
using (SPSite siteCollection = new SPSite(http://localhost/)
{
    using (SPWeb myWeb = siteCollection.RootWeb)
    {
        myWeb.AllowUnsafeUpdates = true;
        // Below doesn't work in 2010
        myWeb.Properties.Add("thenewkey", "The NewValue");
        myWeb.Update();
        myWeb.AllowUnsafeUpdates = false;
    }
}
Instead, You need to use the new AddProperty() method.

using (SPSite siteCollection = new SPSite(http://localhost/)
{
    using (SPWeb myWeb = siteCollection.RootWeb)
    {
        // The key must be lower-case
        myWeb.AddProperty("thenewkey", "The NewValue");
        myWeb.Update();
    }
}

Notes:
 
  1. If you use the "AddProperty()" method, you don't need the AllowUnsafeUpdates shown in many examples on the web.
  2. For backward compatibility, stick to lower case keys. Mixed case keys can be stored and retrieved using the new 2010 methods but are invisibile to older code that uses the Properties collection. (More information: http://trentacular.com/2009/06/sharepoint-the-wicked-spwebproperties-propertybag/)
  3. There are many examples on the internet that don't work. Here are just two:
  4. The clue to all why all the other examples don't work (thanks Nancy): http://sharepoint.mindsharpblogs.com/NancyB/archive/2011/06/29/The-Sandboxed-Solutions-and-SPWeb.AllProperties-Puzzle.aspx



Thursday, September 1, 2011

Provisioning Wiki Pages in SharePoint 2010 Web Template

By now, you may have noticed that the venerable Web Part Page we all knew and loved in SharePoint 2007 is being replaced by the Wiki page in 2010.  The main difference is that Wiki pages can accept HTML intermixed with web parts, which gives you more layout options.

This posting is about how to provision Wiki pages into a library from a Web Template definition.  There doesn't seem to be much information about how to do this and there are a couple of tricks that took us quite some time to figure out.  Hence, this post.

The goal is to create a web template that includes pages pre-populated into the SitePages library. It works a little bit like provisioning a Web Part Page, but there are a couple of hidden and poorly documented additions.

I'm assumng that you already have a web template to start with and just want to add Wiki pages to the SitePages library.

Phase 1 - Getting the Raw Material

  1. Create the Page in SharePoint. Add web parts and edit HTML until you're happy with it.
  2. Save the Site into the Solution Gallery (From Site Settings, select Save site as template)
  3. Download the Solution (Open the Solution Gallery and download the file)
  4. Import the WSP into a new Visual Studio 2010 project. This is a working project from which you'll extract the components you'll need.
  5. Open another copy of Visual Studio with Your Live Project
Phase 2 - Moving components

You'll need to locate and copy the following components. 
  1. In SitePages_DocumentTemplates: Copy the Elements.xml file into your live project.  This contains the basic page definitions.  (More about the contents of this file later).
  2. PropertyBags.  Locate and copy the entries for your library and file(s) to your live project.  This contains the HTML used to generate pages at runtime.
Phase 3 - Package, Deploy and Test

Using Visual Studio, build and package the solution.  Add the solution to your SharePoint server and create a test site. 

How I Think it Works

As I mentioned, documentation on this is extremely scarce, but here are some notes about how I think the Wiki page works and how it differs from the old Web Part Page.

At first glance the CAML for Wiki pages appears to be identical to Web Part Pages. but there are several important differences:
  1. In the File element, the Path must be set to "wkpstd.aspx" which is the base Wiki page.  Your page is rendered using this page as a starting point.
  2. As before, web parts added to the page are declared using AllUsersWebPart elements, but
    1. The WebPartOrder attribute has no effect on display order
    2. The WebPartZoneID is always "wpz"
    3. The ID is set to a GUID used to locate the HTML (See below)
  3. Inside the Wiki web part there are two properties that contain the HTML used in the body of the web part.  These are encoded using HTMLEncode.  These are:
    1. MetaInfo
    2. WikiField 
  4. In the PropertyBag element, the WikiField described above is repeated.  It appears that this HTML is what is actually used when the web part is rendered. The HTML inside the Web Part spec doesn't seem to be used.
The GUID in the Web Part ID attribute appears in the HTML in the WikiField.  I believe the code that renders the Wiki web part uses the GUIDs to determine where in the HTML to insert the web parts.

Thursday, March 17, 2011

About SharePoint 2010 Site Templates

I've been struggling with SharePoint site templates lately and have learned some valuable things. There's too much for one post. I'm hoping to have time to write a series that, taken together might be helpful.

This post is about the big picture and the main lessons.

Here's the scenario:
  1. You've built yourself a nice SharePoint site on your development server. Let's say it contains custom web parts, workflows, site columns, pages and content types.
  2. Now, it's time to package this up into a template and move to another server (say a test or production server). You want to use the template to create multiple copies of your site.
  3. SharePoint 2010 has improved capabilities over SharePoint 2007 but the new features come with their own limitations and complexity. That's what I want to write about.

The naive SharePoint developer will read the documentation and assume that this is all you need to do:

  1. Save the site as a template in the Solution Gallery.
  2. Download the WSP
  3. Either upload the WSP to the new server's gallery or deploy it using Central Administration.

Here's an example of the naive approach. Unfortunately, it creates lots of problems and only works on the simplest of sites.

Here's a short list of the problems:

  • The template includes lots of stuff you don't need and probably don't want on the destination server including content types and site columns from the root site. The site definition includes dependencies on all site-collection features on the source server even if they're not needed.
  • Because of all the extra stuff, the destination server needs to be almost identical to the source server. If it isn't, it won't work. Unless your template is extremely simple, this will prevent you from creating sites using your template until you've essentially re-installed all the dependent features (even the ones you don't use).
  • Features are given unfortunate names like "Web template of exported site MySite"
  • The template will clone the theme of the source site. New sites based on the template will appear to be using a standard Theme, but they are not. Site administrators who want to control look and feel will not be happy with this.

Visual Studio 2010 includes a wizard that can import WSPs. This is a huge time saver over what we had to do before. Unfortunately, this too has more than a few pitfalls. The upshot of these pitfalls is that, while it works, you should expect to spend quite a bit of time adjusting things before a truly useful and portable template can be generated.

Click here for a video that shows the basic Visual Studio WSP import process.

A quick summary of the pitfalls of importing WSPs into Visual Studio 2010:

  1. As mentioned above, the WSP that SharePoint creates contains a lot of stuff you don't need and don't want. The wizard allows you to avoid loading those items into the project, but the process is very tedious and it's easy to make mistakes. (A typical import will include more than 150 elements and each has to be selected individually).
  2. The resulting solution has a very odd and complex structure. Elements that could have easily been combined are separate. For example, a list instance is in one element while Edit, Upload, View pages are in another. Neither element is useful without the other and they can readily be combined. Why they're separate is a mystery.
  3. The arrangement of elements into features is very odd. In general, the import wizard seems to create lots of features when a few would do just fine. Again, the default names are most unfortunate.
  4. If you want to create your template in iterations, the only process that works is very tedious and error prone. Basically, you have to re-export the site, import it into a working project then manually transcribe the changes into your production project.

So, here's a more realistic process for creating "real" templates:

  1. Create the template on your development server.
  2. Save it into the Solution Gallery
  3. Import it into Visual Studio, omitting SharePoint-standard content types and site columns.
  4. Save the solution in your source code control system.
  5. Rename the features to something meaningful.
  6. Open the onet.xml file and remove dependencies on features you aren't using and don't need.
  7. Build the WSP.
  8. Test the WSP on another server.
  9. Fix whatever isn't working right.

When it comes time to produce a newer version of the template:

  1. Save the improved template to the Solution Gallery
  2. Import it into Visual Studio as a working copy.
  3. Open another copy of Visual Studio with your production template.
  4. Locate the changes and transcribe them to the new project.
  5. Build and test the new WSP.

Tuesday, January 18, 2011

Finding references to Content Types

This SQL script can be used to tell you where a content type is used. This is useful if you want to get rid of a stray content type created by InfoPath or workflow tools.

(Reposted from here)

DECLARE @ContentTypeName nvarchar(128)
SET @ContentTypeName='PC Review Task'

SELECT
w.Title AS [Web Site],
w.FullUrl AS [Web Url],
al.tp_Title AS [List Title],
ct2.*
FROM ContentTypes ct1
JOIN ContentTypes ct2 ON LEFT(ct2.ContentTypeId, Len(ct1.ContentTypeId))=ct1.ContentTypeId
LEFT OUTER JOIN dbo.ContentTypeUsage ctu ON LEFT(ctu.ContentTypeId, Len(ct2.ContentTypeId)) = ct2.ContentTypeId
LEFT OUTER JOIN dbo.AllLists al ON ctu.ListId = al.tp_Id AND ctu.WebId=al.tp_WebId
LEFT OUTER JOIN dbo.Webs w ON al.tp_WebId = w.Id
WHERE ct1.ResourceDir=@ContentTypeName

Sunday, January 2, 2011

InfoPath Tips and Tricks

TFS

  • Manual check-out and check-in is necessary. The InfoPath Designer lacks a source code control plug-in.

  • Create a folder "_Published" below the folder containing your InfoPath form. Check the folder into TFS, but do not check any contents.

  • Create a folder called "Code" below the folder containing the InfoPath form. Check all folder contents in.

Source Code


  • Be sure to reset the code location (on Form Options) to point to the Code folder described above. The default location is in the "My Documents" folder, which is useless for source code control.
  • Each time you work on a new InfoPath form, it will be necessary to reset the code location folder. (This option is retained in InfoPath, not the template.)

Publishing

  • Set the publish location folder to "_Published" folder created above. Do not check the published file into TFS.
  • Reset the publish location every time you work on a different InfoPath form.
  • Generally speaking, publish all forms for "Administrator Approval"
  • Don't let InfoPath create content types for you. Do that ahead of time.
  • Be sure to check the "Allow users to edit data in this field using a datasheet or property page" for all promoted properties. This will allow the workflow to easily change them.

If you're wondering why all the rules, most of the issues are due to to things:

  1. InfoPath Designer is unaware of source code control.
  2. InfoPath Designer seems to have been designed with the idea in mind that a developer only works on one form at a time.
  3. InfoPath can make a mess of your SharePoint content types.