Microsoft® SharePoint® 2013 Developer Reference: Data Provisioning

  • 5/15/2013

Content types

A content type schema defines a model for a specific SharePoint complex data type, and is based on a set of site column references, together with some other optional information related to forms, rendering templates, a specific document template (only in the case of document items), and custom XML configuration.

Chapter 2 “SharePoint data fundamentals,” showed how SharePoint uses a hierarchical structure for defining content types, which consists of a base content type named System with a single child named Item. SharePoint then applies an inheritance paradigm (similar to object-oriented class inheritance) to define each content type descendant of Item. Figure 3-1 shows an excerpt of the hierarchical inheritance tree for native content types. As a consequence of this behavior, you must define inheritance information for each new content type that you declare. For more details, read the “Content type IDs” section later in the chapter.

Listing 3-3 provides an example of the Contact content type, defined by referencing a set of site columns.

Figure 3-1

Figure 3-1 The content types inheritance hierarchy in SharePoint.

LISTING 3-3 A simple content type defined in a feature element, together with its site columns

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!-- Site Columns used by the Content Type -->
  <Field
    ID="{C7792AD6-F2F3-4f2d-A7E5-75D5A8206FD9}"
    Name="DevLeapContactID"
    StaticName="DevLeapContactID"
    DisplayName="Contact ID"
    Type="Text"
    Group="DevLeap Columns"
    Sortable="TRUE" />
<Field
    ID="{A8F24550-55CD-4d34-A015-811954C6CE24}"
    Name="DevLeapCompanyName"
    StaticName="DevLeapCompanyName"
    DisplayName="Company Name"
    Type="Text"
    Group="DevLeap Columns"
    Sortable="TRUE" />
  <Field
    ID="{149BF9A1-5BBB-468d-AA35-91ACEB054E3B}"
    Name="DevLeapCountry"
    StaticName="DevLeapCountry"
    DisplayName="Country"
    Type="Choice"
    Group="DevLeap Columns"
    Sortable="TRUE">
      <Default>Italy</Default>
      <CHOICES>
        <CHOICE>Italy</CHOICE>
        <CHOICE>USA</CHOICE>
        <CHOICE>Germany</CHOICE>
        <CHOICE>France</CHOICE>
      </CHOICES>
  </Field>
  <!-- Parent ContentType: Item (0x01) -->
  <ContentType ID="0x0100A60F69C4B1304FBDA6C4B4A25939979F"
               Name="DevLeapContact"
               Group="DevLeap Content Types"
               Description="Base Contact of DevLeap"
               Inherits="TRUE"
               Version="0">
    <FieldRefs>
      <FieldRef
        ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}"
        Name="Title"
        DisplayName="Full name" />
      <FieldRef
        ID="{C7792AD6-F2F3-4f2d-A7E5-75D5A8206FD9}"
        Name="DevLeapContactID"
        DisplayName="Contact ID"
        Required="TRUE" />
      <FieldRef
        ID="{A8F24550-55CD-4d34-A015-811954C6CE24}"
        Name="DevLeapCompanyName"
        DisplayName="Company Name" />
      <FieldRef
        ID="{149BF9A1-5BBB-468d-AA35-91ACEB054E3B}"
        Name="DevLeapCountry"
        DisplayName="Country" />
    </FieldRefs>
  </ContentType>
</Elements>

This feature element example contains a ContentType element, which defines some descriptive information, such as the Name, Group, and Description. The ContentType element also defines a Version attribute, which indeed is used for managing versioning, as its name implies, but is still reserved by Microsoft for future use. Last, but most important, is the ID attribute, which defines the unique identifier for this content type in the site collection where it is defined. Inside the ContentType element is a FieldRefs element, which is the parent of a list of FieldRef or RemoveFieldRef elements. Each element in this list references a specific site column to be added or removed from this content type. You might notice that this example references all the site columns defined earlier in the feature element file. In fact, unless you are defining site columns for use in multiple content types, it’s common to define the referenced site columns within the same feature element file—just before the content type that will use them.

Listing 3-3 also references a site column with the name Title and the ID {fa564e0f-0c70-4ab9-b863-0177e6ddd247}. This is the SharePoint native site column that defines the Title field for each SharePoint item. In the content type example, we changed the DisplayName value from Title, which still retains its internal name, to Full name, which will be the displayed name for this content type. By default, the Title field is also used by SharePoint to render the Edit Control Block menu, which allows you to display, edit, and manage a list item from the list UI.

Content type IDs

The ID attribute of a content type is not a simple GUID, as it was with the site columns definition; instead, it’s a more complex value that describes the hierarchical inheritance of the type. In fact, every content type ID is composed of the ID of its hierarchical parent content type, followed by a hexadecimal value that’s unique to the current content type. You could say that a content type ID defines its genealogy. This logic is recursive, starting with the System content type and extending all the way down to the current content type. Table 3-3 shows an excerpt of the base hierarchy of SharePoint content type IDs.

Table 3-3 An excerpt of the base hierarchy of SharePoint content type IDs

Content type

ID

System

0x

Item

0x01

Document

0x0101

XmlDocument

0x010101

Picture

0x010102

Event

0x0102

Contact

0x0106

Task

0x0108

Folder

0x0120

Table 3-3 demonstrates that the root content type is System, which is a special hidden content type with an ID value of 0x. The Item content type is the only child of System and has an ID value of 0x01 (the System ID + 01). The Document content type, which is a child of Item, has an ID value of 0x0101 (the Item ID + 01), while its sibling Event has an ID of 0x0102 (the Item ID + 02).

In general, the rule used to define content type IDs states that you can build an ID using either of two techniques:

  • Parent content type ID + two hexadecimal values (cannot be 00)
  • Parent content type ID + 00 + hexadecimal GUID

Microsoft generally uses the first technique to define base content type IDs. Third parties, such as vendors or ISVs, typically use the latter technique to define custom content type IDs. If you want to define a hierarchy of custom content types of your own, follow these steps:

  1. Identify the base content type from which you want to inherit.
  2. Add 00 at the end of the base content type ID.
  3. Add a hexadecimal GUID just after the 00.
  4. Append two hexadecimal values to declare every specific child of your content type.

As a concrete example, suppose that you want to define a custom content type inherited from the Document base content type. You would start with 0x0101, which is the Document ID, append 00 to it, and then append a hexadecimal GUID, making your ID something like 0x010100BDD3EC87EA65463AB9FAA5337907A3ED.

If you wanted to use your custom content type as a base for some other inherited content types, you would append 01, 02, and so on for each child content type, as in the following:

  • Base ID 0x010100BDD3EC87EA65463AB9FAA5337907A3ED
  • Child 1 0x010100BDD3EC87EA65463AB9FAA5337907A3ED01
  • Child 2 0x010100BDD3EC87EA65463AB9FAA5337907A3ED02

With that in mind, we can go back to the example custom Contact content type. First, you need to choose the base content type from which you want to inherit. For example purposes, assume that you decide to use the generic base Item as the parent content type. That means the custom content type ID will start with 0x01, followed by 00 and then a hexadecimal GUID. The end result is the same as the ID highlighted in bold in Listing 3-3:

ID="0x0100A60F69C4B1304FBDA6C4B4A25939979F"

The goal of the case study is to define a custom list that is based on a couple of content types (Customer and Supplier) inherited from this base Contact content type. Listing 3-4 shows the definitions of the Customer and Supplier content types.

LISTING 3-4 Customer and Supplier content type definitions

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Field
      ID="{AC689935-8E8B-485e-A45E-FF5A338DD92F}"
      Name="DevLeapCustomerLevel"
      StaticName="DevLeapCustomerLevel"
      DisplayName="Customer Level"
      Type="Choice"
      Group="DevLeap Columns">
    <Default>Level C</Default>
    <CHOICES>
      <CHOICE>Level A</CHOICE>
      <CHOICE>Level B</CHOICE>
      <CHOICE>Level C</CHOICE>
    </CHOICES>
  </Field>
  <Field
      ID="{A73DE518-B9B9-4e8d-9D94-6099B4603997}"
      Name="DevLeapSupplierAccount"
      StaticName="DevLeapSupplierAccount"
      DisplayName="Supplier Account"
      Type="User"
      Group="DevLeap Columns"
      Sortable="TRUE" />
  <ContentType ID="0x0100A60F69C4B1304FBDA6C4B4A25939979F01"
               Name="DevLeapCustomer"
               Group="DevLeap Content Types"
               Description="Customer of DevLeap"
               Version="0">
    <FieldRefs>
      <FieldRef
          ID="{AC689935-8E8B-485e-A45E-FF5A338DD92F}"
          Name="DevLeapCustomerLevel"
          Required="TRUE" />
    </FieldRefs>
  </ContentType>
  <ContentType ID="0x0100A60F69C4B1304FBDA6C4B4A25939979F02"
               Name="DevLeapSupplier"
               Group="DevLeap Content Types"
               Description="Supplier of DevLeap"
               Version="0">
    <FieldRefs>
      <FieldRef
          ID="{A73DE518-B9B9-4e8d-9D94-6099B4603997}"
          Name="DevLeapSupplierAccount"
          Required="TRUE" />
    </FieldRefs>
  </ContentType>
</Elements>

Both of these content types extend the base Contact content type; each adds a specific site column. The Customer content type adds a required field to define the customer level (A, B, or C) for each Customer instance, while the Supplier content type adds a field to reference a local account, which you can browse as a SharePoint user. You can see the inheritance hierarchy of these custom types in Figure 3-2, which shows a portion of the Site Content Type page of a site collection.

Figure 3-2

Figure 3-2 The Site Content Type page of a site collection where the custom content types are provisioned.

Finally, consider that Visual Studio 2012 automatically calculates the content type IDs when you add a new content type to a SharePoint project. In fact, if you try to add a content type to a SharePoint project within Visual Studio 2012, you will be prompted with a one-step wizard, regardless of whether you are creating a Windows SharePoint Services Solution Package (WSP) or a SharePoint app. In the wizard’s first and only step, you must choose the basic content type from which you would like your custom content type to inherit ( Figure 3-3).

Figure 3-3

Figure 3-3 The wizard for creating a new content type.

After you make your choice and click finish to close the wizard, SharePoint displays a graphical designer useful to define the columns of the content type and its overall configuration. Figure 3-4 shows the two tabs available in the Content Type designer: Columns and Content Type.

Figure 3-4

Figure 3-4 The two tabs available in the Content Type designer

As you can see, the Columns tab is active. Here you can reference the site columns to use in the current content type. Note, however, that you can specify existing site columns only. The Content Type tab enables you to define the name, the description, and the group of the current content type. Lastly, through this second tab you can also determine whether the content type will inherit columns from its parent type or not, as well as if the current type will be read-only and/or hidden. Based on your settings, the designer creates an XML element manifest file that is similar to what you can code manually. Although this might seem like a worthwhile shortcut, it is somewhat limited. When you need a finer degree of flexibility in defining custom content types, manually creating or editing the XML file is a better solution.

More about content types

Sometimes you need a more restricted content type; in such cases, SharePoint offers several other interesting attributes to help you out. For example, the ReadOnly attribute makes the content type read-only when its value is set to TRUE. Likewise, when the Sealed attribute is set to TRUE, it seals a content type so that only a site collection administrator using the Server Object Model can unseal it for editing. Lastly, the Hidden attribute is useful for making a content type invisible so that contributors cannot create new items of this type in list views, but you will still have access to it through your custom code. If you want to declare a content type as completely invisible—not only for end users but also for site collection administrators—you can make it belong to a special group named _Hidden.

In addition, you can configure a content type not only through ContentType element attributes, but also by declaring some child elements. One of these is the FieldRefs child element discussed earlier in this chapter. Another useful element is XmlDocuments, with which you can define any kind of custom XML configuration to apply to the content type. SharePoint itself uses this element to declare custom controls and pages for the content type. Listing 3-5 shows how to use this element.

LISTING 3-5 Using the XmlDocuments element inside a content type definition

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType ID="0x0100a60f69c4b1304fbda6c4b4a25939979f01"
               Name="DevLeapCustomer"
               Group="DevLeap Content Types"
               Description="Customer of DevLeap"
               Inherits="TRUE"
               Version="0">
    <FieldRefs>
      <FieldRef
        ID="{AC689935-8E8B-485e-A45E-FF5A338DD92F}"
        Name="DevLeapCustomerLevel"
        Required="TRUE" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI=
       "http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
        <FormTemplates xmlns=
          "http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
          <Display>DevLeapCustomerDisplay</Display>
          <Edit>DevLeapCustomerEdit</Edit>
          <New>DevLeapCustomerNew</New>
        </FormTemplates>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

Listing 3-5 shows that the XmlDocuments element is just a container for one or more XmlDocument elements. Every XmlDocument element can have a NamespaceURI attribute that declares the scope of the custom configuration defined. Listing 3-5 declares a configuration that defines custom ASCX control files that are used for rendering display, edit, and add forms for instances of the current content type. The ASCX control files referenced should be deployed inside the CONTROLTEMPLATES special folder of SharePoint, through a farm-level (full-trust) solution. The content of each XmlDocument element derives from the referenced NamespaceURI. The only requirement is that the XML content must be valid against its declared XML schema.

When you consider that in a farm-level (full-trust) solution you can access any custom XmlDocument that you define while provisioning content types later through the Server Object Model, you can see that the model provides you with an extremely customizable environment.

Document content types

Content types inherited from the Document base content type (ID: 0x0101) are a special case that you must analyze a bit more carefully than usual. In fact, every document has numerous specific configurations that it must handle. For instance, in the “Content types” section earlier in the chapter, you learned that a document can have a document template, a document information panel, or both.

Listing 3-6 shows the definition for a custom document content type that declares an Invoice document model.

LISTING 3-6 Defining the Invoice content type, inherited from the Document content type

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!-- Parent ContentType: Document (0x0101) -->
  <ContentType ID="<b>0x0101</b>00A5FD8267A91945DF9F3884D9EAA4F12F"
               Name="DevLeapInvoice"
               Group="DevLeap Content Types"
               Description="Invoice of DevLeap"
               Inherits="TRUE"
               Version="0">
    <FieldRefs>
      <!-- Field References here -->
    </FieldRefs>    
    <DocumentTemplate TargetName="Forms/DevLeapInvoiceTemplate.dotx" />
  </ContentType>
</Elements>

The Document portion of the ID is highlighted in bold to remind you of the underlying behavior of SharePoint. The DocumentTemplate element (also highlighted) has a TargetName attribute that defines the URL (relative for the site collection) of the template item to use for every new Invoice instance. Listing 3-7 shows how to define a custom document information panel for a Document content type, assuming that you have already designed and deployed the panel.

LISTING 3-7 Defining a custom document information panel for an Invoice content type, inherited from the Document content type

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!-- Parent ContentType: Document (0x0101) -->
  <ContentType ID="0x010100a5fd8267a91945df9f3884d9eaa4f12f"
               Name="DevLeapInvoice"
               Group="DevLeap Content Types"
               Description="Invoice of DevLeap"
               Inherits="TRUE"
               Version="0">
    <FieldRefs>
      <!-- Field References here -->
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI=
        "http://schemas.microsoft.com/office/2006/metadata/customXsn">
        <xsnLocation>http://URL/customXsn.xsn</xsnLocation>
        <cached>False</cached>
        <openByDefault>True</openByDefault>
        <xsnScope>http://URL/documentLibrary</xsnScope>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

Listing 3-7 declares the absolute URL of the document information panel by using the xsnLocation element. It also disables caching in the Microsoft Office client by setting the cached element to FALSE. Lastly, it defines how the document should behave relative to this new panel, through the openByDefault element, which is set to TRUE, meaning that the panel should open by default. The xsnScope element is required, but for now it is reserved by Microsoft for internal use only.