Thursday 3 January 2013

Adding a new field to a content type by upgrading a feature

Working with content types that are already deployed can be tricky.
Working with feature upgrade is a pain in the b... as well. In fact I'm amazed how poorly it is handled in SharePoint taking into consideration how common a task it should be.

Quite often you need to add an extra field to a content types which has already been deployed and associated with a list.

After a lot of trying I finally found a solution that is working for me.


Vesa Juvonen has made a very good blog on the subject here:

WebTemplate training materials – Lab 4 - Upgrading existing sites with feature versioning


It's a fairly big and complex thing, so will not rewrite it all here.
But in short terms the things you have to do and be aware of is:

  • Make a new Elements.xml for your new field.
  • Do NOT add the field to the existing content type Elements.xml file!
  • In the xyz.Template.xml file for your feature that deploys your content type (= the feature you want to upgrade), add UpgradeActions, ApplyElementManifests, CustomUpgradeAction (see snippet below)



  <UpgradeActions>
    <VersionRange BeginVersion="0.0.0.0" EndVersion="3.0.0.0">
     
      <ApplyElementManifests>
        <ElementManifest Location="FieldsV2\Elements.xml" />
      </ApplyElementManifests>

      <CustomUpgradeAction Name="AddFieldToContentType">
        <Parameters>
          <Parameter Name="FieldId">58757B21-3BDD-4AC7-BCE5-ACFC025735E2</Parameter>
          <Parameter Name="ContentTypeId">0x0100906acb18801a416680c0017602a462d7</Parameter>
          <Parameter Name="UpdateChildren">true</Parameter>
        </Parameters>
      </CustomUpgradeAction>
     
    </VersionRange>


  • Add an event reciever for the feature and implement the FeatureUpgrading method. Here programmatically add the new field to the content type.


        public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
        {
            SPWeb web = ((SPSite)properties.Feature.Parent).RootWeb;
            switch (upgradeActionName)
            {
                case "AddFieldToContentType":
                    string fieldId = parameters["FieldId"];
                    string contentTypeId = parameters["ContentTypeId"];
                    bool updateChildren = true;
                    bool flag;
                    updateChildren = bool.TryParse(parameters["UpdateChildren"], out flag);
                    UpdateManager.AddFieldToContentType(web, contentTypeId, fieldId, updateChildren);
                    break;

                default:

                    break;
            }

        }


        public static void AddFieldToContentType(SPWeb web, string contentTypeId, string siteColumnId, bool updateChildren)
        {
            try
            {
                SPContentType type = web.ContentTypes[new SPContentTypeId(contentTypeId)];
                type.FieldLinks.Add(new SPFieldLink(web.Fields[new Guid(siteColumnId)]));
                type.Update(updateChildren, updateChildren);
            }
            catch (Exception ex)
            {
                // TODO write to log
                //throw;
            }
        }

  • Now implement the FeatureActivating method in a similar manner in order to make the upgraded functionality of the feature available for new installations of the feature as well (else it will only get added when the feature is upgraded).
  • Now deploy your wsp package. After it is deployed you must programmatically upgrade the feature. This is done by first making a query on features that needs upgrading, and then calling the Upgrade methode on the feature. This can be done with C# code or in PowerShell.

In this approach the CustomUpgradeAction tag was used in the fefature template.xml file. There is also a out of the box tag for adding a feature to an existing content type which can be used. It is called: "AddContentTypeField". However I have not have any success with using this. I have read that it should not work reliably with all culumative updates of SharePoint. Mayby trhis is why? I'm not sure. However I can not work with it. You could have a scenario where it works in your development environment, but not in production.

No comments:

Post a Comment