RSS
Add to Technorati Favorites
Follow me on Twitter


Becky Bertram's Blog > Posts > Updating Content Types and Site Columns That Were Deployed as a Feature
Updating Content Types and Site Columns That Were Deployed as a Feature
How many times have you come across this scenario? You create several Site Columns as well as a Content Type or two in your Feature. Then you want to update it. Since you deployed it via a Feature (as opposed to editing it in the browser), being a good developer, you decide you want to execute your update through a Feature as well. However, you run into several problems:
  • When you deactivate your Feature, it keeps some Site Columns and deletes other ones.
  • You notice some of the Site Columns and Content Types are still hanging around in the lists you applied them to, even after you deactivated your Feature.
  • You try doing an in-place upgrade of your Feature, and nothing happens; everything looks exactly like before. The columns in your Content Type haven't changed or anything.

This can be very confusing and aggravating, and this is a scenario I've walked through with several clients. Why does this happen? And what should be a proper approach for upgrading a Feature that includes Site Columns or Content Types?

Site Columns and Content Types in List
When you add a Content Type, or a Site Column, to a list, SharePoint actually makes a copy of that item in the list. However, the copy seems to retain the same GUID/Identifier as the original item. This allows several things:

  • This acts as a "delta" of sorts; when you add a Site Column to a list you can say, "I want to use this Site Column, except in this list, I want it to display 7 lines of text instead of 6," etc. By having a copy, SharePoint can modify the properties of your Site Column or Content Type in your list, while keeping it separate from the "original" version in your Site Collection root. The same applies for Content Types: what if you wanted to attach a Workflow to your Content Type, just for this list? It needs a copy of that Content Type in that list.
  • Have you noticed how, when you're modifying a Site Column or a Content Type, you have that little check box that asks if you want to push your change down to everything that uses it? You have two choices: either you will, or you won't. If you don't want to apply your changes to existing items, how would SharePoint handle that? Well, it essentially leaves the existing copies of the Site Columns that are applies to lists alone, and just uses your changes when creating new copies of that Site Column in the future. By using a copy of the Site Column in lists, it's possible to have multiple definitions for a Site Column being used at once.
  • If you decide you do want to apply your changes to everything that uses that item, how does SharePoint do it? Essentially, it looks for any Site Column or Content Type in the site collection hierarchy that is using the same GUID (or ID, the case of a Content Type). That provides a sort of implicit connection between the two. (Think of it like siblings: they're different people, but they have the same last name and the same parents.)

Deactivating Your Feature
What happens when you deactivate your feature? Typically, if a Site Column or Content Type is not being referenced in any list or anywhere else in the site, SharePoint will remove it from the Site Collection. However, if it's being used, SharePoint will often delete the ones that aren't be used, but leave the ones that are. On occasion, deactivating the Site Columns will actually remove the items. However, the copies of the assets will remain in the underlying lists. This might seem confusing at first, but it's because the lists contain copies. (Using our analogy again, if siblings' parents go on vacation, the siblings still retain their last name and their sibling relationship, whether the parents are around or not.)

I'd like to add a little caveat here: I have run into many issues with SharePoint when it comes to modifying Site Columns and Content Types using Features, whether it means changing the Site Column type, changing the composition of Content Types, etc. Because SharePoint is keeping track of multiple versions of these assets, you can easily get it confused, especially if you try to change the very field type of a Site Column. The purpose of this blog entry is to make this easier for you. However, I strongly recommend you have a clean development environment to work on, since once you run into a mismatch in show SharePoint handles its Site Columns or Content Types, it has the possibility of disrupting operations for your whole Site Collection.

Activating Your Feature
If we think about it in reverse, what happens when we activate a feature? SharePoint uses the CAML markup we used to define our Site Column or Content Type, and it puts it into the database. This is a one-type event. What do I mean by that? If you create a Master Page via a Feature, you do put a reference to that Master Page in SharePoint, so that you get your new Master Page showing up in the Master Page Gallery for your site. However, all that reference does is point to the file system. Any time SharePoint to use that Master Page, it says, "Hmm, looks like I should look at the file on the file system in the Features folder instead of a file stored in my database." However, with Content Types, once the Feature has been activated, SharePoint uses the CAML to add the Site Column or Content Type to its database, and it never uses that asset on the file system again. Basically, it's the same as using a Feature Receiver that executes code once when the Feature is activated, and never again. (Please note: I have no inside information from Microsoft about this! This is just what I've inferred based on the behavior of these assets.)

Creating Site Columns and Content Types Using a Feature Receiver
So this begs the question, why not just use a Feature Receiver that executes code which instantiates these things into SharePoint, and just forget the CAML markup altogether? Well, remember what we were saying about the relationship between GUIDs in the lists and their parent items in the Site Collection? It's often important that if you're activating and deactivating a Feature in a Site Collection that the GUIDs remain the same, so-as to prevent orphaning those assets in the child lists. Furthermore, if you're activating the Feature in multiple Site Collections, you probably want continuity between the assets in different Site Collections.

When you create a new Site Column via code, using the SiteColumnCollection.Add() method, SharePoint automatically creates a GUID for that Site Column. The only way you could hard-code that GUID would be to create the Site Column by passing in the entire XML definition. Well, if you're going to do that, you might as well just use the CAML way of doing things. And what about Content Types? I looked, and I don't even see a way of specifying the unique identifier for a Content Type. It's true, you can pass in the parent Content Type, and the way SharePoint constructs ID's for Content Types, its ID includes the ID of its parent. However, I have found of no way of passing in what the newly-created Content Types unique part of the ID should be. (If you're confused about what I'm talking about when referring to Content Type IDs, take a look here: http://msdn.microsoft.com/en-us/library/aa543822.aspx.)

Recommended Approach
Based on all these factors, my suggestion is this:

  • Create two Features: one for the original markup and one for making changes. (Or you can put them in the same Feature; I just want to differentiate between where you do what.)
  • The original Feature should contain the CAML for Site Columns and Content Types. This ensures the IDs have been assigned ahead of type and remain constant.
  • If you want to update a Site Column by changing nearly anything about it except its Field type, do it using a Feature Receiver. By doing this, you can call the Update method and pass in a boolean indicating if you want all the existing assets in the site that inherit from this to update to, (something you couldn't do via the CAML.)
  • You can also add an existing Site Column (that you provisioned via the CAML feature) to an existing Content Type (that was provisioned via the CAML feature). This is helpful if the Column was not part of that Content Type before, etc.
  • In a scenario like the one I just mentioned in the last bullet point, it's necessary to deactivate and reactive the CAML feature (to provision the new assets) before calling your Feature Receiver. What will this mean for the site? Since all the Site Columns and Content Types in the lists in the site are using the same ID's as the ones provisioned in the Site Collection root, removing its parent from the Site Collection won't change that. It might leave it orphaned temporarily, (i.e. there will be no relationship between that item and an item in the Site Collection root, but it will function the same way it always has, since it's really a fully-functioning copy of the original item) until you reactivate the Feature that puts the item back in the Site Collection. It's like the parents are going on vacation when you deactivate the Feature, and are coming back home when you activate the Feature again.

You have a choice when it comes to how you maintain the CAML and the Feature Receiver, since you have two scenarios: existing Site Collections and new ones.

  • You could make a policy that every time you write code in your Feature Receiver to update a Site Column or Content Type, you have to make the change in your CAML as well. That would mean that every time you activated the CAML Feature in a "fresh" Site Collection, the CAML would be up-to-date and accurate; there would be no need to run the "updater" feature. (In your Feature Receiver, you should make sure you do some extra checking to make sure a Site Column doesn't already belong to a Content Type before adding it, etc. in case that change is already in place before the code executes.) This approach means you only have to execute one Feature when creating a new Site Collection, but it also means you're maintaining changes in two places: in your Feature Receiver for making changes to existing sites, and in your CAML for new sites. It's a cleaner approach, but also contains an element of redundancy, which always leaves room for human error.
  • The other approach is to simply assume that every time the base CAML feature is activated, you're always going to execute the Feature Receiver. This approach says the only time you'd change the CAML is to add a new Site Column or new Content Type; otherwise, all the changes happen in the Feature Receiver. This approach reduces redundancy, but also means your Feature Receiver code could get quite large with all your changes over time, and it could leave your CAML as very much "legacy" over time.

Deleting Site Columns and Content Types
If you've noticed, I haven't written much about deleting Content Types and Site Columns. That's because deleting a Column could easily mean deleting the content stored in that Column. As we've already noted, deleting a Site Column won't delete the copies of that Site Column from lists in the site that use it. If you want to delete a Column from a list, you'll need to write code that will explicitly allow this, since it means you'll also lose any content that was stored in that column in the list. You'll have to explicitly set a property called AllowDeletion on the SPField object you're trying to delete.

In terms of deleting a Content Type from a site, the same thing goes, in terms of deleting a Content Type from the Site Collection root won't necessarily remove the copies of that Content Type in lists. Also, removing a Content Type from a List after the Content Type has been removed from the Site Collection won't necessarily remove the Columns from the list, if it now thinks those Columns are just part of its own definition, and not a Content Type's columns.

In my experience, this is where things can get hairy, since you're dealing with copies without parents, etc. It's imperative that you do things in the right order, and practice in a development environment before trying to execute this sort of scenario in production.

Conclusion
Dealing with the issue of updating Site Columns and Content Types in SharePoint can be a tricky issue when using Features, but hopefully this will provide you some guidance about how to carry this out in your own environment.

Comments

Great Post

Hi Becky great blog, i am having lots of issues with deploying content types and site columns and content types via feature.
The reason of your approach is when we updating a content type that is installed on a feature, if we update something of the content type when we reactivating the content type this changes won't be on the child content types on the list right? This is because when we update the caml of the parent content type the child content type on the list remains without change?
I have one problem, i deactivate one feature with lots of content types, some of the content types didn't delete, because it were on some list, then i delete all the content types from all the list and now when i want to delete the content type i get an error something like this: the content type belongs to a feature and can't be deleted... Did you go through this problem? I can't delete this content types!! :(

Removing Existing Content Types

Unfortunately, you cannot remove Content Types that have been activated by a Feature, without deactivating that Feature. (I have found this annoying when I didn't want my site to display the typical "Article Page", "Welcome Page", etc. that Publishing sites provision automatically.) If it's your Feature that provisioned the Content Types, deactivate your Feature. Otherwise, you can write code that hides them, so they don't show up to the user when they browse the Content Types of the site.

When you update a Content Type using the SharePoint API (not CAML), you can pass in a Boolean to the Update() method, that specifies that all Content Types that reference this one should be updated. That's why I recommend, if you're going to add a NEW content type, add it to the CAML. If you're going to change an EXISTING content type, do it with code.

Great questions!

Re: Updating Content Types and Site Columns That Were Deployed as a Feature

Becky the problem is the feature is deactivated but the content type is not deleted because it was been using on a list, so i delete the content of the list, and i can't delete the content type, with the feature deactivated, this is very frustating, because the error says that the content type is part of a feature but the feature is not activated...
Another strange behaviour is, if you add a content type on a list, the you remove the content type of the list, all the fields of the content type remains on the list... But when you are going to create a item on that list, these fields doesn't appear. This must be a bug, what do you think?

SPSource

Becky,

You may also want to look at some of the other tools out there such as STSDev and SPSource in combination to reverse engineer Content TYpes and Site Columns you create in the Web Interface and then pushing this straight intoa Visual Studio project that can be deploy as a Feature in a Solution Package. Check out my latest presentation on my blog for more information.

Jeremy Thake
http://wss.made4the.net

Cheers,
Jeremy Thake

Re: Updating Content Types and Site Columns That Were Deployed as a Feature

Jeremy could you please put the link to go directly to your artcile?
Thanks!

Re: Updating Content Types and Site Columns That Were Deployed as a Feature

Hi Becky,

great post and good starting point for a reference to see how complex it all is. I've written a post that keeping all contenttypes and sitecolumns accross sitecollections is really a must have in certain scenario's and it's not really do-able because of all the pitfalls. Let me know what you think ;)

http://community.zevenseas.com/Blogs/Robin/archive/2008/10/12/upgradeable-features-andor-webapplication-contenttypes.aspx

Great article

Great post Becky! I've dealt with this issue in the past and this is a very thoughtful look at all the major considerations.

Mrs.

Hi Becky - I found your blog just googling a few keywords on the Web. I have a STL client that is looking for a SharePoint Developer with large-scale deployment experience for a contract position. Is this something you would be interested in? If not, do you know of anyone in the STL area that would be? Please send them my way:

adriane.yates-cook@phase5consulting.com.

Thanks!!

Some more test cases...

Hi Becky

I spent quite a bit of time testing out a few scenarios with updating and creating new Content Types + Site Columns. have a look and let me know your thoughts.

http://www.collaboris.co.uk/blogs/mark/09-05-16/Upgrading_Site_Columns.aspx

Approach

Hi, Thanks for your recommended  suggestions.
 

Comment Title *


Your Name


Body *


Your E-mail Address


Your Website

Type the Web address: (Click here to test)  

Type the description: 

Post Date *

Post Title *