This is the 3rd and last part in a small series on how to create a custom information management policy for SharePoint 2007.
In part 1 the policy was introduced and we created the policy feature and created the setup control that allows our users to configure the policy.
Part 2 shows how to create the handler that actually does some work and submits a document to the records center
The final part will put it all together. It also has all code attached. You can find the zip file at the bottom of this article.
Step 1 – Registering the PolicyFeature
In the first part we implemented the IPolicyFeature interface, but it didn’t do anything. The first method we will implement is the Register method. This is called when the policy is assigned to a content type. This is the perfect place if you need to do some extra configuration. I will do 2 things here:
- Setup an event receiver for the content type.
- Add an extra site column (and create if it doesn’t exist) to the content type.
To setup an event receiver for the content type, we’ll add this code to the register method:
Assembly assembly = Assembly.GetExecutingAssembly();
SPEventReceiverDefinition eventReceiver = ct.EventReceivers.Add();
eventReceiver.Name = "Policy of Truth";
eventReceiver.Type = SPEventReceiverType.ItemUpdated;
eventReceiver.SequenceNumber = 200;
eventReceiver.Assembly = assembly.FullName;
eventReceiver.Class = "TST.POC.PolicyFeatures.PolicyOfTruthHandler";
eventReceiver.Update();
The event receiver itself will be implemented in one of the next steps. The code to setup the site column to the content type is added below. This will first check if a field with internalname “SentToTruthRepository” is available in the content type. If it is not it will check if this field is available as a site column. If the site column is not yet available, it will create it as a readonly site column. The value of this field will only be updated by our policy, and users should not be able to change it manually. This last bit adds the site column to the Content Type.
string fieldName = "SentToTruthRepository";
// test if field is linked to content type
foreach (SPFieldLink link in contentType.FieldLinks)
if (link.Name == fieldName)
return;
SPField repositoryField = null;
using (SPWeb web = contentType.ParentWeb)
{ // check if site column exists in the site
foreach (SPField field in web.AvailableFields)
{ if (field.InternalName == fieldName)
{ repositoryField = field;
break;
}
}
// add site column if it does not exist
if (repositoryField == null)
{ string xml = "<Field Name=\"SentToTruthRepository\" FromBaseType=\"FALSE\" Type=\"DateTime\" ";
xml += "DisplayName=\"Sent to truth repository\" Required=\"TRUE\" Format=\"DateTime\" ";
xml += "ReadOnly=\"TRUE\" Group=\"Policy Columns\" />";
string newField = web.Fields.AddFieldAsXml(xml);
repositoryField = web.Fields.GetFieldByInternalName(newField);
}
}
// add field to content type
SPFieldLink newLink = new SPFieldLink(repositoryField);
contentType.FieldLinks.Add(newLink);
contentType.Update(true);
Step 2 – Unregistering the policy
The method UnRegister on the policy feature is called when a policy is detached from a content type. This is the place to unregister the event handler that we created in the first step. You can also remove the extra site column from the content type, but I decided to leave it.
public void UnRegister(Microsoft.SharePoint.SPContentType ct)
{ if (ct == null)
{ throw new ArgumentException();
}
SPEventReceiverDefinition delete = null;
foreach (SPEventReceiverDefinition eventReceiver in ct.EventReceivers)
{ if ((eventReceiver.Name == "Policy of Truth") && (eventReceiver.Type == SPEventReceiverType.ItemUpdated))
{ delete = eventReceiver;
break;
}
}
if (delete != null)
delete.Delete();
}
Step 3 – Creating the event handler
The next step is to create the event handler we used in step 1. This will use the handler we created in the previous part. This handler check the item for the policy rules and submits the item to the records center. The event handler is a normal event reveiver for SharePoint list event. For demo purposes I have only implemented the ItemUpdated event.
public class PolicyOfTruthHandler : SPItemEventReceiver
{ public override void ItemUpdated(SPItemEventProperties properties)
{ DisableEventFiring();
RepositoryHandler repository = new RepositoryHandler();
if (repository.HandleListItem(properties.ListItem))
{ string truthFieldName = "Sent to truth repository";
properties.ListItem[truthFieldName] = DateTime.Now;
properties.ListItem.Update();
}
EnableEventFiring();
}
}
The RepositoryHandler you see here is the handler I created in the previous part of this series. The code to update the list item and set the date in the special site column, has moved from the repository handler to the event handler. The eventhandler first calls DisableEventFiring() to prevent the update of the list item by the policy from firing the event a second time. For the update this works, but for some strange reason the ItemUpdated event fires twice in the process. As soon as we call the SubmitFile method on the OfficialFile.asmx webservice, the event gets fired a second time. This way we end up with 2 documents in the records center each time we change an item. I’ve spent quite a bit of time trying to stop this, but I didn’t succeed. I decided to leave it as is, because I wanted to get the policy working and it is not a real world scenario.
Step 4 – The rest of the policy feature
Our policy feature also implements the method “ProcessListItem”. According to the policy sample in the ECM Starter Kit (MOSS SDK), this method is called for list items of the content type that were added before the policy was in place. Items that we not handled by the vent handlers (because the event handlers were not there yet) will we processed by ProcessListItem when the policy is assigned. I tried to test this using my custom policy of truth, but couldn’t get it to work.
To be a full working solution our policy should also implement the OnCustomDataChange method. This is called when the custom setup of the policy is changed. In our case this is when an administrator changes the keywords. Our policy feature should then check which documents are considered as ‘truth documents’ and these should be added to the records center.
Step 5 – Testing the solution
Here are the steps how I tested the custom policy:
- Create a new content type called “Whitepaper”
- Create a new custom policy for this content type. Activate the Policy of Truth and set the keywords to SharePoint and WSS

- Assign the content type to a document library

- Upload a new document to the document library and set the title to “The truth on SharePoint development”

- Navigate to your records center and test if your document was submitted to the records center. It should be submitted as an unclassified record. Please note that my testdocument was uploaded twice. I explained the reason for that above in step 3.

- Open one of the xml files in the “Properties” folder and notice that we also set a custom property while submitting the file to the repository: ‘SubmittedBy’.

- Go back to the document library that has the document we just added. Change the view to include the field “Sent to truth repository” field. Notice that this field now has a value. This was set by the policy after successfully submitting the document to the records center.

Overview of all parts:
- Part 1 – introduction and creating the policy feature
- Part 2 – implementing the handler and submitting to a records center
- Part 3 – implementing and testing the policy