I was recently having a conversation with one of my co-workers over provisioning document templates within a feature for one of our current projects. There were several examples available from random blogs within easy reach to anyone with a browser, internet access, and you favorite search engine. Although the examples I found to be technically correct they all seemed to overly complicate the process of setting up a content type and provisioning an associated document template within a feature.
Before I jump into the approach I typically use let do a quick review of SharePoint document templates. SharePoint provides the ability to associate document content types with document templates. These can be word documents, excel documents, whatever your needs are. These content types can then be associated with a document library. This provides the ability for a new documents to be created, based on the provided template, and associated with the desired meta data found in the content type. Once configured your document template and associated content type will appear in the new item options dropdown within your document library. It’s worth mentioning that document libraries themselves can have default templates but the real power comes with the combination of multiple content types and default templates for a single document library.
Building The Feature
The core of any feature is the associated elements file(s) – this is were all the provisioning instructions are provided. For our purpose we’re going to be working with four specific elements:
- <Field> – Define our Site Columns that will be part of our content type.
- <ContentType> – Define our Content Type, the associated document template, and associated site columns (fields). Our content type is based on the base document content type indicated by a content type ID beginning with 0x0101.
- <ListInstance> – Optionally create a new document library that our content types will be associated with.
- <ContentTypeBinding> – Associates our content type with a document library.
- <Module> – Provisions our document template referenced within the <ContentType> element.
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Provision Site Column -->
<Field Type="Choice"
DisplayName="DocumentType"
StaticName="DocumentType"
Name="DocumentType"
Required="FALSE"
Format="Dropdown"
FillInChoice="FALSE"
Group="MyCompany"
ID="{c2cad809-5336-4d62-b8aa-ed8e55b0b200}"
SourceID="http://schemas.microsoft.com/sharepoint/v3">
<CHOICES>
<CHOICE>Finance</CHOICE>
<CHOICE>Sales</CHOICE>
</CHOICES>
</Field>
<!-- Provision Content Type and associate the document template -->
<ContentType ID="0x0101003C32228299AD46c5B47688879AEBD5AB" Name="Corporate Document" Group="My Document">
<FieldRefs>
<FieldRef ID="{c2cad809-5336-4d62-b8aa-ed8e55b0b200}" Name="DocumentType" Required="TRUE" />
</FieldRefs>
<DocumentTemplate TargetName="/_cts/Corporate Document/documenttemplate.docx" />
</ContentType>
<!-- Provision the document template in system content types virtual folder -->
<Module Name="DocumentTemplates" Url="_cts/Corporate Document" RootWebOnly="TRUE" Path="DocumentTemplates" >
<File Url="documenttemplate.docx" Type="Ghostable" />
</Module>
<!-- Optionally create a new document library and associate the new content type(s) -->
<ListInstance TemplateType="101"
RootWebOnly="false"
Id="CorpDocuments"
Title="CorpDocuments"
Url="CorpDocuments"
OnQuickLaunch="true"
FeatureId="00BFEA71-E717-4E80-AA17-D0C71B360101">
</ListInstance>
<ContentTypeBinding ContentTypeId="0x0101003C32228299AD46c5B47688879AEBD5AB" ListUrl="CorpDocuments" />
</Elements>
It’s worth noting depending on your needs you may need to add a feature receiver to your feature to enable content type management on the list by default and to set default content types. Unfortunately this can’t be accomplished declaratively in the elements file.
The following is a snippet for establishing a default content type when you are just dealing with a single content type although it could be easily modified for ordering more then one content type in addition to setting the default. It also enables the management of content types on the list.
private void SetDefaultContentType(SPList list, string defaultContentTypeName)
{
SPContentType defaultContentType = list.ContentTypes[defaultContentTypeName];
list.ContentTypesEnabled = true;
SPFolder folder = list.RootFolder;
SPContentType[] orderedContentTypes = new SPContentType[1];
orderedContentTypes[0] = defaultContentType;
folder.UniqueContentTypeOrder = orderedContentTypes;
folder.Update();
}
Working With Templates Through Code
For most end users new documents will be created through the browser. At times however, such as within workflows, you may want to create new documents based on the available templates dynamically through code. The following technique is the approach I typically make to creating new documents based on content type templates for libraries with multiple content types (and associated templates):
SPList docLibrary = web.Lists["CorpLibrary"];
SPContentType docContentType = docLibrary.ContentTypes["Corporate Document"];
//Get a reference to the template file for the content type and load it into a raw byte array
SPFile docTemplateFile = web.GetFile(docContentType.DocumentTemplateUrl);
byte[] rawTemplateFile = docTemplateFile.OpenBinary();
//Create the new item and file based on the template
SPFile newFile = docLibrary.RootFolder.Files.Add("newdocument.docx", rawTemplateFile);
//Update the content type for the new item and any desired fields
newFile.Item["ContentTypeId"] = docContentType.Id;
newFile.Item["DocumentType"] = "Sales";
newFile.Item.Update();
One alternative approach suggested by a co-worker is to make use of the default content type. Each library can optionally contain a default content type. New items make use of the default content type when a specific content type isn’t selected in a dropdown. By using this technique you can optionally avoid the steps of getting a reference to the template file and updating the content type because the docLibray.Items.Add will create the document for you and set the content type but this makes the assumption that your desired document template is always the default template of the list. Yes you can dynamically modify the default template of the list at run time but this could lead to some undesirable side affects in an actively use document repository with its default content type changing frequently.
As you can see the creation of default templates for content types is pretty straight forward and you can achieve more reuse in your environments by implementing the solution through a feature as opposed to manually through the browser.