ECM in MOSS 2007: Site Columns en Content Types
Sinds de release van de eerste SharePoint Portal Server versie (SPS 2001) is er veel gebeurd op het vlak van Enterprise Content Management (ECM) in SharePoint. Functionaliteiten als versiebeheer, check-in check-out en approval workflows hebben zich ontwikkeld tot onmisbare tools voor online samenwerken aan documenten en voor het publiceren van content. Hoewel dit zich met SPS 2003 ontwikkeld heeft tot een platform voor het opslaan van enterprise content, was er een aantal punten waar nog veel te behalen viel.
Met de introductie van het Office System 2007 platform, in de vorm van Windows SharePoint Services 3.0 (WSS 3.0) en Microsoft Office SharePoint Server 2007 (MOSS 2007), is ECM naar een hoger niveau gebracht. Denk hierbij aan major en minor versiebeheer, workflow, document conversion, policies, site columns en content types.
In dit artikel wordt dit laatste onderdeel belicht, waarbij vooral gekeken wordt naar de aspecten voor de ontwikkelaar, zoals het creëren van custom field types en het verpakken van deze onderdelen in SharePoint Features.
De case: hardware inventarisatie
In veel organisaties zijn er verschillende typen hardware te vinden zoals PC’s, printers, switches, etc. Voor een ICT-afdeling is het noodzaak om een goed beeld te krijgen van welke hardware waar is, hoeveel garantie er nog op zit en wat de specificaties zijn. In dit geval gaan we SharePoint 2007 inzetten als opslag medium voor deze informatie.
NB: in dit artikel wordt er gebruik gemaakt van de Engelse versie van MOSS 2007 en zijn de gebruikte termen in het Engels.
Site Columns
Site Columns zijn herbruikbare kolomdefinities of kolomtemplates die gebruikt kunnen worden in verschillende SharePoint lijsten en in verschillende SharePoint sites. Door gebruik te maken van site columns, is het mogelijk gecentraliseerd kolommen te specificeren en te beheren en daarbij eventuele wijzigingen te pushen naar bestaande instanties van deze kolommen.
In ons geval maken we kolommen om de metadata van de hardware in op te slaan. Voorbeelden hiervan zijn:
- Naam van de hardware (‘Hardware name’, tekstveld)
- IP nummer (‘IP Number’, tekstveld)
- Aanschafdatum (‘Order Date’, datumveld)
- Type hardware (‘Hardware Type’, keuze veld)
We kunnen nu deze velden gaan aanmaken in de SharePoint omgeving. Ga hiervoor naar ‘Site Actions’, ‘Site Settings’ en dan naar ‘Top level site settings’. Onder de kop ‘Galleries’, klik op ‘Site columns’ om de site kolommen voor deze site collectie te beheren. We creëren hier de kolommen zoals hierboven genoemd en groeperen ze onder de categorie ‘Hardware’ (zie figuur 1).

Fig 1: Site Columns in SharePoint 2007
Nu we de kolommen hebben aangemaakt, is het mogelijk deze in een lijst te gebruiken. We creëren een nieuwe lijst genaamd ‘Hardware’ van het type ‘custom list’ en gaan naar de eigenschappen van de lijst. Onder de kop ‘Columns’ is er de mogelijkheid om bestaande site columns toe te voegen: ‘Add from existing site columns’. We voegen hier alle ‘Hardware’ velden toe (zie figuur 2).

Fig. 2: Toevoegen site columns in een lijst
Uiteindelijk kunnen we nu nieuwe items gaan aanmaken in de lijst, waarbij de nieuwe kolommen gebruikt kunnen worden (zie figuur 3).

Fig. 3: Lijst met nieuwe Site Columns
Als we de site column nu gaan wijzigen, kan aangegeven worden of de wijziging wel of niet wordt doorgevoerd door de bestaande instanties van de kolom.
We hebben nu met behulp van de SharePoint interface de site columns aangemaakt. Echter, voor ontwikkeling in een andere omgeving en deployment naar verschillende andere omgevingen, is dit een tijdrovend werk. We kunnen deze kolommen ook eenvoudig deployen via het Feature Framework van SharePoint. In dit artikel gaan we niet in op de precieze werking van het Feature Framework, maar in het kort zorgt het framework ervoor dat elementen als site colums, page layouts, webparts, workflows en andere custom onderdelen, op eenvoudige wijze gedeployed kunnen worden in een SharePoint 2007 omgeving. Deze Features bestaan uit een of meerdere XML bestanden waarin het een en ander geconfigureerd wordt. Onze Feature bestaat uit twee XML bestanden (zie listing 1 en listing 2).
Title="HardwareColumns"
Description="Custom culumns for ICT"
Version="12.0.0.0"
Scope="Site"
DefaultResourceFile="core"
xmlns="http://schemas.microsoft.com/sharepoint/">
Listing 1: Site Column: feature.xml
In de Feature wordt een verwijzing gemaakt naar columns.xml, waarin de site columns gedefinieerd staan (listing 2).
xmlns="http://schemas.microsoft.com/sharepoint/">
Name="HardwareName"
SourceID=
"http://schemas.microsoft.com/sharepoint/v3"
StaticName="HardwareName"
Group="Hardware (via feature)"
Type="Text"
DisplayName="Hardware Name" />
Name="HardwareType"
SourceID=
"http://schemas.microsoft.com/sharepoint/v3"
StaticName="HardwareType"
Group="Hardware (via feature)"
Type="MultiChoice"
DisplayName="Hardware Type">
PC
Printer
Switch
Name="IPNumber"
SourceID=
"http://schemas.microsoft.com/sharepoint/v3"
StaticName="IPNumber"
Group="Hardware (via feature)"
Type="Text"
DisplayName="IP Number" />
Name="OrderDate"
SourceID=
"http://schemas.microsoft.com/sharepoint/v3"
StaticName="OrderDate"
Group="Hardware (via feature)"
Type="DateTime"
DisplayName="Order Date" />
Listing 2: Site Column: columns.xml
We kunnen de Feature nu installeren en activeren op de SharePoint omgeving, waarna de hardware site columns te gebruiken zijn (figuur 4).

Fig. 4: Site Columns via Feature gedeployed
Custom Field Types
Nu we de kolommen hebben aangemaakt, zien we dat er bepaalde gebruikersfouten kunnen worden gemaakt. Een voorbeeld hiervan is de kolom ‘IP Number’. Een IP nummer (er vanuit gaande dat IPv4 gebruikt wordt) is een reeks van 4 keer 3 getallen tussen 0 en 255, gescheiden door een punt (bijvoorbeeld 192.168.0.1). In ons geval hebben we een tekstveld gemaakt voor deze metadata, waarmee we niet kunnen forceren dat het nummer op de juiste manier wordt ingevuld.
In deze gevallen kunnen we ervoor kiezen gebruik te maken van custom field types, een eigen gemaakte data type. Een custom field type kan gemaakt worden in Visual Studio 2005. We starten hiervoor een nieuw project van het type Class Library.
Allereest specificeren we in de class ‘IPNumberValue’ (listing 3) hoe het custom field intern er uit ziet. In dit geval bestaat het veld uit vier nummers, die we hier specificeren.
Imports Microsoft.SharePoint
Public Class IPNumberValue
Inherits SPFieldMultiColumnValue
Private Const numberOfColumns As Integer = 4
Public Sub New()
MyBase.New(numberOfColumns)
End Sub
Public Sub New(ByVal value As String)
MyBase.New(value)
End Sub
' First IP number
Public Property FirstNumber() As String
Get
Return Me.Item(0)
End Get
Set(ByVal value As String)
Me.Item(0) = value
End Set
End Property
' Second IP number
Public Property SecondNumber() As String
Get
Return Me.Item(1)
End Get
Set(ByVal value As String)
Me.Item(1) = value
End Set
End Property
' Third IP number
Public Property ThirdNumber() As String
Get
Return Me.Item(2)
End Get
Set(ByVal value As String)
Me.Item(2) = value
End Set
End Property
' Fourth IP number
Public Property FourthNumber() As String
Get
Return Me.Item(3)
End Get
Set(ByVal value As String)
Me.Item(3) = value
End Set
End Property
End Class
Listing 3: IPNumberValue.vb
Hierna kunnen we het custom field zelf specificeren waarin we overerven van het SPFieldMultiColumn object. Op deze manier specificeren we dat het custom field uit meerdere (interne) SharePoint kolommen bestaat (listing 4).
Imports Microsoft.SharePoint
Imports Microsoft.SharePoint.WebControls
Friend Class IPNumber
Inherits SPFieldMultiColumn
' Methods
Public Sub New(ByVal fields As SPFieldCollection, _
ByVal fieldName As String)
MyBase.New(fields, fieldName)
End Sub
Public Sub New(ByVal fields As SPFieldCollection, _
ByVal typeName As String, _
ByVal displayName As String)
MyBase.New(fields, typeName, displayName)
End Sub
Public Overrides Function GetFieldValue( _
ByVal value As String) As Object
If String.IsNullOrEmpty(value) Then
Return Nothing
End If
Return MyBase.GetFieldValue(value)
End Function
' Properties
Public Overrides ReadOnly Property _
FieldRenderingControl() As BaseFieldControl
Get
Dim contr As BaseFieldControl = _
New IPNumberControl
contr.FieldName = Me.InternalName
Return contr
End Get
End Property
End Class
Listing 4: IPNumber.vb
Als derde class (listing 5) gaan we de server control specificeren waarin we de afhandeling van de waarden en foutmeldingen doen. Hierbij worden ook de vier tekstvelden gegenereerd die gaan dienen als invoerveld voor het server control.
Imports Microsoft.SharePoint
Imports System.Web.UI.WebControls
Imports Microsoft.SharePoint.WebControls
Friend Class IPNumberControl
Inherits BaseFieldControl
' Declare controls
Protected tbFirstNumber As TextBox
Protected tbFourthNumber As TextBox
Protected tbSecondNumber As TextBox
Protected tbThirdNumber As TextBox
Protected Overrides Sub CreateChildControls()
If (Not Me.Field Is Nothing) Then
MyBase.CreateChildControls()
If (Not Me.ControlMode = SPControlMode.Display) _
Then
Me.tbFirstNumber = DirectCast( _
Me.TemplateContainer.FindControl _
("tbFirstNumber"), TextBox)
If (Me.tbFirstNumber Is Nothing) Then
Throw New ArgumentException("Error")
End If
Me.tbFirstNumber.TabIndex = Me.TabIndex
Me.tbFirstNumber.CssClass = Me.CssClass
Me.tbFirstNumber.ToolTip = "Between 0 and 255"
Me.tbSecondNumber = DirectCast( _
Me.TemplateContainer.FindControl _
("tbSecondNumber"), TextBox)
If (Me.tbSecondNumber Is Nothing) Then
Throw New ArgumentException("Error")
End If
Me.tbSecondNumber.TabIndex = Me.TabIndex
Me.tbSecondNumber.CssClass = Me.CssClass
Me.tbSecondNumber.ToolTip = "Between 0 and 255"
Me.tbThirdNumber = DirectCast( _
Me.TemplateContainer.FindControl _
("tbThirdNumber"), TextBox)
If (Me.tbThirdNumber Is Nothing) Then
Throw New ArgumentException("Error")
End If
Me.tbThirdNumber.TabIndex = Me.TabIndex
Me.tbThirdNumber.CssClass = Me.CssClass
Me.tbThirdNumber.ToolTip = "Between 0 and 255"
Me.tbFourthNumber = DirectCast( _
Me.TemplateContainer.FindControl _
("tbFourthNumber"), TextBox)
If (Me.tbFourthNumber Is Nothing) Then
Throw New ArgumentException("Error")
End If
Me.tbFourthNumber.TabIndex = Me.TabIndex
Me.tbFourthNumber.CssClass = Me.CssClass
Me.tbFourthNumber.ToolTip = "Between 0 and 255"
If (Me.ControlMode = SPControlMode.[New]) Then
Me.tbFirstNumber.Text = Me.Field. _
GetCustomProperty("FirstNumber").ToString
Me.tbSecondNumber.Text = Me.Field. _
GetCustomProperty("SecondNumber").ToString
Me.tbThirdNumber.Text = Me.Field. _
GetCustomProperty("ThirdNumber").ToString
Me.tbFourthNumber.Text = Me.Field. _
GetCustomProperty("FourthNumber").ToString
End If
End If
End If
End Sub
Protected Overrides ReadOnly Property _
DefaultTemplateName() As String
Get
Return "IPNumberRendering"
End Get
End Property
Public Overrides Property Value() As Object
Get
Me.EnsureChildControls()
Dim value2 As New IPNumberValue
value2.FirstNumber = Me.tbFirstNumber.Text
value2.SecondNumber = Me.tbSecondNumber.Text
value2.ThirdNumber = Me.tbThirdNumber.Text
value2.FourthNumber = Me.tbFourthNumber.Text
Return value2
End Get
Set(ByVal value As Object)
Me.EnsureChildControls()
Dim value2 As IPNumberValue = DirectCast(value, _
IPNumberValue)
Me.tbFirstNumber.Text = value2.FirstNumber
Me.tbSecondNumber.Text = value2.SecondNumber
Me.tbThirdNumber.Text = value2.ThirdNumber
Me.tbFourthNumber.Text = value2.FourthNumber
End Set
End Property
End Class
Listing 5: IPNumberControl.vb
Na het schrijven van de classes, gebruiken we een user control (listing 6) om de controls die gebruikt worden in de server control vorm te geven. Deze control wordt gebruikt bij het invoeren van nieuwe items, of het bewerken ervan.
<%@ Control Language="VB" Debug="true" %>
<%@Assembly Name="Microsoft.SharePoint,
Version=12.0.0.0,
Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@Register TagPrefix="SharePoint"
Assembly="Microsoft.SharePoint,
Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"
namespace="Microsoft.SharePoint.WebControls"%>
ID="IPNumberRendering"
runat="server">
MaxLength="3" Size="5" runat="server"/>.
MaxLength="3" Size="5" runat="server"/>.
MaxLength="3" Size="5" runat="server"/>.
MaxLength="3" Size="5" runat="server"/>
Listing 6: IPNumber.ascx
Als laatste specificeren we het field type in de vorm van XML, waarbij onder andere de default waarden gespecificeerd worden en de rendering van de waarde bij het weergeven van de custom field type in de vorm van CAML (listing 7).
Name="TypeName">IPNumber
Name="ParentType">MultiColumn
Name="TypeDisplayName">IP Number
Name="TypeShortDescription">IP Number
Name="UserCreatable">TRUE
Name="ShowOnListAuthoringPages">TRUE
Name="ShowOnDocumentLibraryAuthoringPages">
TRUE
Name="ShowOnSurveyAuthoringPages">
TRUE
Name="ShowOnColumnTemplateAuthoringPages">
TRUE
Name="FieldTypeClass">
HardwareFieldTypes.IPNumber,
HardwareFieldTypes, Version=1.0.0.0,
Culture=neutral,
PublicKeyToken=020dc925af4f767f
DisplayName="First Number"
MaxLength="3" DisplaySize="5" Type="Text">
0
DisplayName="Second Number"
MaxLength="3" DisplaySize="5" Type="Text">
0
DisplayName="Third Number"
MaxLength="3" DisplaySize="5" Type="Text">
0
DisplayName="Fourth Number"
MaxLength="3" DisplaySize="5" Type="Text">
0
HTMLEncode="TRUE"/>
HTMLEncode="TRUE"/>
HTMLEncode="TRUE"/>
HTMLEncode="TRUE"/>
Listing 7: fldtypes_IPNumber.xml
Nu het custom field type gemaakt is, moeten we ervoor zorgen dat deze gedeployed wordt binnen de SharePoint omgeving. Hiervoor moet de UserControl geplaatst worden in de ‘CONTROLTEMPLATES’ folder binnen de SharePoint ‘TEMPLATE’ folder op het filesysteem. Daarnaast moet de ‘fldtypes_IPNumber.xml’ geplaatst worden in de ‘XML’ folder binnen de ‘TEMPLATE’ folder. Na een ‘IISRESET’ is het custom field beschikbaar binnen de SharePoint omgeving.
Nu het custom field type gedeployed is, is het mogelijk een kolom aan te maken op basis van het custom field type (figuur 5). Bij het invullen van de waarde (figuur 6) is te zien dat er in dit geval alleen gebruik gemaakt kan worden van vier getallen, door een punt gescheiden (figuur 7).

Fig. 5: Aanmaken Custom Field in lijst

Fig. 6: Invullen IP nummer

Fig. 7: Weergave IP nummer in lijst
Content Types
Om te helpen met het organiseren van content in SharePoint, is het mogelijk om verzamelingen van kolommen te groeperen in content types. Op deze manier onstaat er een set van metadata welke hergebruikt kan worden binnen verschillende sites en lijsten. Daarnaast is het ook mogelijk om een hiërarchie te maken van content types, waarbij de set van metadata wordt hergebruikt.
Als voorbeeld kan een content type ‘Hardware’ worden aangemaakt (figuur 8), met daarin de site kolommen ‘Name’, ‘Type’ en ‘Order Date’.

Fig. 8: Aanmaken Content Type
Elke instantie van het content type ‘Hardware’ bevat nu deze kolommen. Daarnaast kan er nu een tweede content type ‘PC’ worden aangemaakt (figuur 9), welke overerft van het type ‘Hardware’. Het tweede content type verrijken we met de site column ‘IP number’. Elke instantie gebaseerd op dit type, heeft nu een extra kolom met IP nummer.

Fig. 9: Site Columns binnen het Content Type

Fig. 10: Content Types binnen een lijst
Op deze manier kan content centraal worden ingedeeld op een logische, eenvoudig te beheren manier. Net als met site columns kunnen we deze content types verpakken in een Feature (listing 8 en listing 9) en deployen op de server.
Id="{BD656564-344B-4e0a-9CBB-4AC95DFC883E}"
Title="HardwareContentTypes"
Description="Content types for ICT"
Version="12.0.0.0"
Scope="Site"
DefaultResourceFile="core"
xmlns="http://schemas.microsoft.com/sharepoint/">
Listing 8: Content Type: feature.xml
xmlns="http://schemas.microsoft.com/sharepoint/">
ID="0x0100A8ABF285F2D80C4786494122ED847457"
Name="Hardware (feature)"
Group="Hardware Types (feature)"
Description="Hardware Content Type"
Version="1">
ID="{CC5A31EF-CCD5-4ed4-A691-2D343B320EA2}"
Name="Hardware Name" />
ID="{14789E3B-B65E-11b4-A98A-6690576ADE66}"
Name="Hardware Type" />
ID="{B1105775-D16E-42ea-ABA1-1C38DD153823}"
Name="Order Date" />
ID="0x0100A8ABF285F2D80C4786494122ED847457
00A8ABF285F2D80C4786494122ED847417"
Name="PC (feature)"
Group="Hardware Types (feature)"
Description="PC Content Type"
Version="1">
ID="{B1105775-D16E-42ea-ABA1-1C38DD453823}"
Name="IP Number" />
Listing 8: Content Type: contenttypes.xml
Ook nu zien we (figuur 11) dat na installatie en activatie op de server de content types beschikbaar zijn binnen de SharePoint omgeving.

Fig. 11: Content Types via Feature
Conclusie
Binnen het SharePoint 2007 platform zien we dat veel inrichting gedaan kan worden zonder dat er veel code bij komt kijken. Het inrichten van site columns en content types is een goed voorbeeld wat door een consultant of informatieanalist gedaan kan worden.
Een van de valkuilen echter is dat deployment op verschillende omgevingen een probleem op kan leveren, zeker bij complexere structuren. In deze gevallen is het eenvoudig gebruik te maken van het Feature Framework van SharePoint.
In dit artikel hebben we gezien hoe we gebruik kunnen maken van site columns, custom field types en content types, en hoe deze verpakt kunnen worden in Features, zodat ze op consistente wijze gedeployed kunnen worden op verschillende omgevingen.