Defining and Connecting Information (Expiration) Policies

Recently I came across the requirement to add a retention policy (expiration policy) to a content type in the context of a contract management solution. So I created a document library and content types for different types of contracts. The content types in turn can have so called policies, i.e. policies can be attached to the content types. Once attached, these policies call a specified workflow, once a condition is fulfilled. This condition may be fulfilled once a certain date is reached, i.e. a timespan has passed since a specified date in time. The timespan may be one of these: (“years”, “months”, “days”)

The docLib, the and the cTypes that was easy. Connecting the policy was what I had to research. So let’s just assume that has been done and focus on the interesting stuff.

SPWeb web = null; // ... the web, init using either SPContext or using-statement from SPSite Object
string name = "MyContentNameInWeb"; // ... the name of the content type
string workflowName = "MyWorkflowInWeb"; // ... the name of the workflow
// this is a general method for retrieving the content type from the web by name
SPContentType cType = GetContentTypeByName(web, name);
SPWorkflowTemplate tpl = GetWorkflowByName(web, workflowName); // ... get a workflow from the web context

So the code above is plain setting-up. Get a web…I don’t care how you do it. Get the content type you want the policy to be attached to and now get ready to create / attach it:

/// Gets the customized custom data for a workflow triggering.
/// The workflow template that is subsequently triggered.
/// The time span ('days', 'months', 'years').
/// The number of timeSpans.
public static string GetCustomData(SPWorkflowTemplate tpl, String timeSpan, int numberOf)
return @"<data><formula id=""Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn""><number>"
+ numberOf
+ "</number><property>Created</property>"
+ "<period>"
+ timeSpan
+ "</period>"
+ @"</formula><action type=""workflow"" id="""
+ GuidFacade.GetGuidString(tpl.Id)
+ @""" /></data>";

The code you see is a method for getting an xml-string which defines when and what is triggered by the policy. Notice the formula sub-tree which specifies the condition. The id is essential here as it defines the way the information given via the xml is processed. Notice that the name is a qualified name: Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn. So if you want to read up on information policies on msdn that is where to start looking. The dll which contains the policy logic is prefixed with Microsoft.Office. It is not part of the standard Microsoft.SharePoint.dll. Also notice the text-element for the tag <property>. This is the field where the date is stored, that is used for evaluation if the condition is fulfilled. In this case it is the standard field, which is associated to every list (even basic custom list): ‘created’.
You can also see that the value of action type is ‘workflow’, so there are some other types of actions as well, but they are not important in this scenario.

The guidfacade gets a specially formatted guid-string (g.ToString("B").ToUpper()).

string customData = GetCustomData(tpl, "years", 5);
if (Policy.GetPolicy(cType) == null)
//if the content type hasn't got a Policy yet, create a new Policy
Policy.CreatePolicy(cType, null);

Policy policyOfContentType = Policy.GetPolicy(cType);
policyOfContentType.Name = policyName;
string policyFeatureId = “Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration”;
//Add expiration policy to the content type
if (policyOfContentType.Items[policyFeatureId] == null)
policyOfContentType.Items.Add(policyFeatureId, customData);

This last part of code gets the customData from the method of the second code block and checks if a policy is associated with the content type. if not, then it is subsequently created. At this point it is important to remind ourselves that there is a difference between a content type associated to a list or docLib and a content type of a web context. Different policies may be attached to same content types associated with different objects, i.e. a basic content type that is created and therefore attached to the web context may be attached to a list or docLib and afterwards a policy may be added to either one without the policy beeing attached to the other one. That has major implications for the order of statements (attach to list, attach policy != attach policy, attach to list).

If you want the policy to be attached to the content type of the list, then you must use the content type of the list to look-up the according policy (Policy policy = Policy.GetPolicy(cTypeOfList)).

In the end check if there is an expiration policy associated already, if not then add the new expiration. In this case it’s just about vanilla if you check first, my scenario needed an add-no-edit strategy, you can also use a replace-and-give-notice strategy or an add-and-edit strategy if you like.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: