Friday, 21 June 2013

SharePoint 2013 - Why do my Custom Field Type Controls Seem to be Cached and keep Loading Up An Old Version? Some Gotchas for SharePoint Custom Field Types

When creating custom Field Types in SharePoint 2013 (see http://msdn.microsoft.com/en-us/library/jj901637.aspx for examples), there are several steps you need to take to register it with SharePoint. These are all convention-based.

  1. You must create a file called fldtypes_MYFIELDNAMEField.xml e.g. fldTypes_ParentField if you want to add a field called "Parent". SharePoint will pick this field up based on this naming convention for your file.
  2. You need to deploy a user control (e.g. ParentFieldControl.ascx) to the SharePoint HIVE Control Templates directory (it will not work in a subdirectory).
  3. Within the ascx files, you should Specify a rendering Template like so:
<SharePoint:RenderingTemplate ID="ParentFieldControl" runat="server">
    <Template>
        <div class="customFieldType">
        <telerik:RadAutoCompleteBox runat="server" ID="autoCompleteTextBox" CssClass="customFieldControlParentGroupList" Filter="Contains" DropDownHeight="400" DropDownWidth="375" InputType="Token" Delimiter='<%# Constants.DefaultDelimiter %>' DataTextField="Text" ToolTip='<%# DataBinder.Eval(Container.DataItem, "Description")%>' DataValueField="Value">
            <DropDownItemTemplate>

Problem is, I did this and deployed my solution and my changes were not being propagated when my updated custom field was rendered within SharePoint. I tried a few things:

  1. Deleting the field from all lists and the Site fields collection in SharePoint with SharePoint Designer and/or the free tool SharePoint Manager 2013
  2. Removing the Custom Field
  3. Rebooting
Yet my changes weren't being reflected when I deployed the new version. What was going on? Was it some kind of weird caching that persisted between reboots?

What is not clear from the documentation is that the Rendering Template Id MUST be unique between all controls that you deploy as a custom field type. I was REUSING the same DefaultTemplateName and DisplayTemplateName between all controls (following the DRY principle).

I originally thought that it was loading up my control based on the NAME of the ascx control e.g. fieldTypes_ParentField would (by convention) load up the ParentFieldControl.ascx file to perform rendering for that field. This is NOT the case. Instead, the when you override the "DefaultTemplateName" or "DisplayTemplateName" properties on "Microsoft.SharePoint.WebControls.BaseFieldControl", you must ensure that these values have not been used elsewhere by custom fields in your project - otherwise SharePoint will keep picking up the first control it finds with a matching "DefaultTemplateName" or "DisplayTemplateName".

Now because I was reusing the same Template Name between all controls within my ascx files, it was rendering the first control it happened to find - without throwing an exception!

Be warned.

DDK

2 comments:

Frost Michael said...

Hi David,

Thank you for your post, you have resumed in some lines what I had understood during this 4 difficult last months. Very hard subject, my mind.

I have an other problem with Custom Field.
I'm doing a migration from MOSS2003 to SPS2013 and lot of lists use Custom Fields.
The problem is : the migrated columns (with all their contents) do not recognize my new installed field... whereas I have not changed my fldtypes_ file.

About this, are you sure for the "fldtypes_{myCustomField}Field.xml" template name ?
Because I use "fldtypes_{myCustomField}.xml" and it seems to work good.


[So sorry for my terrible English, i'm French]
Again thanks for your post,
Hope to get a quick answer.

Frost Michael said...

Excuse me, I have not clearly expose my question :
How could I recover my custom fields after a migration ? (seems to be the same problem if we would want to transfer between two SPS2013 farm)

If we must install WSP with dll, xml et ascx, how could we link the new field reference with the old column type reference ?

:-)
Thank you in advance.