Upgrading SharePoint Content Types

Introduction

Well it’s now Saturday afternoon and the family have been out shopping all day, so I have taken the opportunity to conduct some tests that I had been meaning to do for a long time now (geek I hear you say). I wanted to find specifically what happens if you want to make changes to Content Types, Columns and Lists that have previously been deployed using Features and CAML. I am going to split my findings up into several posts.

I will detail each set of tests then summarise at the end what I think should be best practice if you want to update these.

Test Cases – Removing Content Types

Can we remove a content type by deactivating the Feature that deployed it?      Yes

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Deactivate the Feature

Outcome:

1. Content type will be removed

2. Feature is deactivated

Can a Content Type can be removed that’s in use by a List?      Yes (and No)

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Reference it in a list

3. Deactivate the Feature

Outcome:

1. Content Type is removed

2. Feature is deactivated

3. List Content Type is still associated with the list

4. The Lists Content Type “Parent” is now amended to be the “Grand Father” Content Type (e.g. the List Content Type gets granddad as its new dad!)

Can an “orphaned” List Content Type be re-parented by reactivating the feature containing the CAML for the real dad?      Yes it can.

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Reference it in a list

3. Deactivate the Feature (list CType gets grandad as the new parent)

4. Reactivate Feature (list CType gets the real dad back)

Outcome:

1. Content Type is re-installed

2. Features is Activated

3. List Content Type is associated with the list

4. List Content Types “Parent” is the Content Type (not the “Grand Father”).

Can we remove a Content Type that’s been customised in the GUI by deactivating a Feature ?      No

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Reference it in a list

3. Change the “name” of the Content Type using the GUI

4. Deactivate the Feature

Outcome:

1. Content Type is not removed

2. Feature is deactivated

3. List Content Type is still associated with the list

4. List Content Types parent is still the real parent

What if we customise a Content Type and then deactivate its Feature? Can we remove the Content Type via the GUI?      No, as it’s in referenced in a List.

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Reference it in a list

3. Change the “name” of the Content Type in the GUI

4. Deactivate the Feature

5. Attempt to Delete the Content Type via the GUI

Outcome:

1. Feature is deactivated

2. List Content Type is still associated with the list

3. List Content Types parent is still the real parent

4. Exception thrown on Delete : “The content type “TestCType123” is part of an application feature”

5. Content Type is NOT removed

Ok, so we have customised the content type in the GUI, deactivated and reactivated the feature and it still won’t go?      Remove all References then it will go!

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Reference it in a list

3. Change the “name” of the Content Type in the GUI

4. Delete the Reference From the List

5. Deactivate and Uninstall the Feature

Outcome:

1. Feature is deactivated

2. Content Type is removed

Test Cases – Updating Content Types

A series of tests were conducted to see if updating the underlying CAML (in the 12 Hive) causes changes to the (already) installed content type…

What can we change by simply editing the CAML XML (within the 12 Hive)?      A Lot more than you would expect!

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Amend the “Group”, “Description”, “Sealed”, “ReadOnly”, “Name” in the CAML (residing in the 12 Hive)

3. Recycle App Pools

Outcome:

1. The Content Type reflects all the changes appropriately

Is there anything we cannot change in the CAML XML (within the 12 Hive)?      Yes, as you would expect its “ID”

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Change the “ID” to something Unique

3. Recycle App Pools

Outcome:

1. The Content Type is no longer available.

2. (Note changing this back to its original ID restores all functionality)

If we corrupt the content type as above (by changing the ID), then what happens if we have list content type depending upon it?      The List Content Type gets grandad as his new dad.

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Reference it in a list

3. Change the “ID” to something Unique

4. Recycle App Pools

Outcome:

1. The Content Type is no longer available

2. The List Content Type is still installed

3. The List Content Type gets parented to the grand parent

4. (Note changing this back to its original ID restores all functionality)

If we customise the content type (in the GUI) then what happens if we change the underlying CAML?      Nothing at all, which will be a pain for most people!

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Amend the “Group” in the GUI to “GUI Group”

3. Change the “Group” in the CAML to “CAML Group”

4. Recycle App Pools

Outcome:

1. The Content Type is installed

2. The Content Types Group reads “GUI Group”

If we customise the content type (in the GUI) then what happens if we change the underlying CAML and the FORCE Activate the Feature?      Nothing at all!

Test Steps:

1. Deploy a Content Type (via Feature and CAML)

2. Amend the “Group” in the GUI to “GUI Group”

3. Change the “Group” in the CAML to “CAML Group”

4. Use “%STSADM% -o activatefeature” (using FORCE)

5. Recycle App Pools

Outcome:

1. The Content Type is installed

2. The Content Types Group reads “GUI Group”

Summary

Here’s a summary of my findings:

  1. If a Content Type is not referenced then it can easily be removed by deactivating the Feature that deployed it.
  2. If a Content Type is referenced by a child List Content Type, then you can still remove the Content Type but this will not delete the List Content Type. In this scenario, you effectively change the parent of the List Content Type to the Parent of the Content Type you just deleted.
  3. If a Content Type is updated by the GUI, or Object Model then the CAML (defining the content type) will be moved into the Database and the relationship with the CAML on the File System is over (with regards to updates). (I am going to do some research into how you can reverse this situation).
  4. If you do want to perform updates to Content Types and you can prevent customisations, then CAML and Upgrade Solutions is a pretty nice way to keep your schema changes owned by your development team.

So, having found all that, if you are running a SharePoint application that requires multiple updates (via Features and WSP’s), it is recommended that you don’t update the Content Type in anyway via the GUI. To prevent GUI updates then perhaps you could make the Content Type read-only and hidden!

As you can understand, this situation isn’t ideal as once you have gone live and updated a content type you are on your own (if you customise via the GUI). Hence, Hugo has been working on an Action to add to SAF (to be released next week), that will allow you to create a Content Type, update it and also push the changes to any children. This will act as a direct replacement for the standard CAML we all currently use. This does mean that from birth your Content Type will always be in the database, but maintainable by XML that lives inside your feature. As soon as they are ready, I will update this post with links to the documentation.

Note. To find out where a Content Type is referenced, we have written an Action in the SharePoint Action Framework (SAF) to do this. The Action is called : “SynchroniseContentTypes”. This action was designed to push down Content Type changes to child Content Types, but, it can also run in Report only mode. When run in this mode it won’t do any updating, but will give you an XML report showing the differences.

To solve these problems (and to give you the best of both worlds), why not try the “Ensure Content Type” Action in SAF. This action takes the same CAML (as you would use in a feature), but SAF processes it, instead of the standard Feature provisioning in SharePoint.