Sunday, 15 July 2012

SharePoint 2010 : Declaratively Create Content Type Based Information Management Policies



“Learn SharePoint from SharePoint” is the principal theme of learning SharePoint for me because what SharePoint says us to do for creating any SharePoint artifact, SharePoint itself does same too. Just have a detailed look at SharePointRoot (14, 12) folder and you will find many working examples there…

Nowadays, I am using Visual Studio 2010 and its development capabilities to facilitate my learning. I will showcase it in this post. Role of Visual Studio in SharePoint development is sadly decreasing. Sometimes it’s not needed to open VS for days or even whole week to complete my development activities. I am not a techie coder but I love VS and it saddens me seeing my beloved VS  loosening its hold in SharePoint development. I just can hope Microsoft not eliminating VS as a development tool in future SharePoint versions. I do not want something I love to go away again….nobody will…

In my attempts to give me chance to open VS, I decided to write some code to create custom Information Management Policies for the content type/ list. As usual I started reading the blogs about creating custom retention/ expiration policies, custom policy formula, custom policy actions. I found two excellent code examples at below links

I also recommend to go through the MSDN documentation on Information Management Policy.

In SharePoint, I always try to accomplish things declaratively rather than programmatically. However, I was wondering whether there is any way to create a custom retention policy declaratively rather than programmatically. I didn't find any declarative example in my extensive googling. Hence I decided to give a try myself and to my surprise I was successful too….all credits to reverse engineering capabilities of VS 2010. Here are the steps.

1.       Create a Custom content type named as ItemWithPolicy.

Figure 1 : Create ItemWithPolicy content type

2.       Using browser, create a retention policy for ItemWithPolicy content type as shown in figure 2 by clicking on Information Management Policy Settings link.

Figure 2 : Create Retention Policy


3.       Save the site as site template with name OOBPolicyExport.wsp and (make sure that Publishing features are deactivated. Otherwise, you won’t find save as site template link in Site Settings page)
4.       Download the site template wsp from Solution gallery and store it in file system.
5.       Create a new VS 2010 project named CreateCustomPolicy using Import SharePoint Solution Package project template. See the figure below.

Figure 3 : Create new VS project


6.       In project creation wizard, in Specify the project source step, select the OOBPolicyExport.wsp from file system and click Next button.
7.       In Select items to import step, first deselect all items and then select the ItemWithPolicy content type item. Click Finish and then No button.
8.       Visual studio will create the definition for ItemWithPolicy content type as shown below. It contains declarative policy too.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
       <ContentType ID="0x0100ED6AA2E224D2E849AC3315D40378E039" Name="ItemWithPolicy" Group="SharePoint Custom Development" Overwrite="TRUE" xmlns="http://schemas.microsoft.com/sharepoint/">
              <Folder TargetName="_cts/ItemWithPolicy" />
              <FieldRefs>
                     <FieldRef ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}" Name="ContentType" />
                     <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="TRUE" ShowInNewForm="TRUE" ShowInEditForm="TRUE" />
                     <FieldRef ID="{b0227f1a-b179-4d45-855b-a18f03706bcb}" Name="_dlc_Exempt" Hidden="TRUE" />
                     <FieldRef ID="{74e6ae8a-0e3e-4dcb-bbff-b5a016d74d64}" Name="_dlc_ExpireDateSaved" Hidden="TRUE" />
                     <FieldRef ID="{acd16fdf-052f-40f7-bb7e-564c269c9fbc}" Name="_dlc_ExpireDate" />
              </FieldRefs>
              <XmlDocuments>
                     <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
                           <spe:Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">
                                  <Receiver>
                                         <Name>Microsoft.Office.RecordsManagement.PolicyFeatures.ExpirationEventReceiver</Name>
                                         <Synchronization>Synchronous</Synchronization>
                                         <Type>10001</Type>
                                         <SequenceNumber>101</SequenceNumber>
                                         <Assembly>Microsoft.Office.Policy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
                                         <Class>Microsoft.Office.RecordsManagement.Internal.UpdateExpireDate</Class>
                                         <Data />
                                         <Filter />
                                  </Receiver>
                                  <Receiver>
                                         <Name>Microsoft.Office.RecordsManagement.PolicyFeatures.ExpirationEventReceiver</Name>
                                         <Synchronization>Synchronous</Synchronization>
                                         <Type>10002</Type>
                                         <SequenceNumber>102</SequenceNumber>
                                         <Assembly>Microsoft.Office.Policy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
                                         <Class>Microsoft.Office.RecordsManagement.Internal.UpdateExpireDate</Class>
                                         <Data />
                                         <Filter />
                                  </Receiver>
                                  <Receiver>
                                         <Name>Microsoft.Office.RecordsManagement.PolicyFeatures.ExpirationEventReceiver</Name>
                                         <Synchronization>Synchronous</Synchronization>
                                         <Type>10004</Type>
                                         <SequenceNumber>103</SequenceNumber>
                                         <Assembly>Microsoft.Office.Policy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
                                         <Class>Microsoft.Office.RecordsManagement.Internal.UpdateExpireDate</Class>
                                         <Data />
                                         <Filter />
                                  </Receiver>
                                  <Receiver>
                                         <Name>Microsoft.Office.RecordsManagement.PolicyFeatures.ExpirationEventReceiver</Name>
                                         <Synchronization>Synchronous</Synchronization>
                                         <Type>10006</Type>
                                         <SequenceNumber>104</SequenceNumber>
                                         <Assembly>Microsoft.Office.Policy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
                                         <Class>Microsoft.Office.RecordsManagement.Internal.UpdateExpireDate</Class>
                                         <Data />
                                         <Filter />
                                  </Receiver>
                                  <Receiver>
                                         <Name>Microsoft.Office.RecordsManagement.PolicyFeatures.ExpirationEventReceiver</Name>
                                         <Synchronization>Synchronous</Synchronization>
                                         <Type>10009</Type>
                                         <SequenceNumber>105</SequenceNumber>
                                         <Assembly>Microsoft.Office.Policy, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
                                         <Class>Microsoft.Office.RecordsManagement.Internal.UpdateExpireDate</Class>
                                         <Data />
                                         <Filter />
                                  </Receiver>
                           </spe:Receivers>
                     </XmlDocument>
                     <XmlDocument NamespaceURI="office.server.policy">
                           <p:Policy xmlns:p="office.server.policy" id="" local="true">
                                  <p:Name>ItemWithPolicy</p:Name>
                                  <p:Description />
                                  <p:Statement />
                                  <p:PolicyItems>
                                         <p:PolicyItem featureId="Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration" staticId="0x0100ED6AA2E224D2E849AC3315D40378E039|-1459032695" UniqueId="9c73ec8f-1cee-49d1-8604-558c24093f57">
                                                <p:Name>Retention</p:Name>
                                                <p:Description>Automatic scheduling of content for processing, and performing a retention action on content that has reached its due date.</p:Description>
                                                <p:CustomData>
                                                       <Schedules nextStageId="2">
                                                              <Schedule type="Default">
                                                                     <stages>
                                                                           <data stageId="1">
                                                                                  <formula id="Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn">
                                                                                         <number>1</number>
                                                                                         <property>Created</property>
                                                                                         <propertyId>8c06beca-0777-48f7-91c7-6da68bc07b69</propertyId>
                                                                                         <period>years</period>
                                                                                  </formula>
                                                                                  <action type="action" id="Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Action.MoveToRecycleBin" />
                                                                           </data>
                                                                     </stages>
                                                              </Schedule>
                                                       </Schedules>
                                                </p:CustomData>
                                         </p:PolicyItem>
                                  </p:PolicyItems>
                           </p:Policy>
                     </XmlDocument>
                     <XmlDocument NamespaceURI="microsoft.office.server.policy.changes">
                           <PolicyDirtyBag xmlns="microsoft.office.server.policy.changes">
                                  <Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration op="Change" />
                           </PolicyDirtyBag>
                     </XmlDocument>
                     <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
                           <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
                                  <Display>ListForm</Display>
                                  <Edit>ListForm</Edit>
                                  <New>ListForm</New>
                           </FormTemplates>
                     </XmlDocument>
              </XmlDocuments>
       </ContentType>
</Elements>

9.       Delete the ItemWithPolicy content type from Site Content Type gallery created through browser.
10.   Add a new List definition with content type project item to project named Declarative Policy Test List and select the ItemWithPolicy content type as associated content type as shown in figure 4.

Figure 4 : Create List definition with content type

11.   Change the List Instance name as Declarative Policy Test List Instance
12.   Deploy the VS project. It will create the list Declarative Policy Test List with ItemWithPolicy content type.
13.   Go to the Site content type gallery and check the Information Management Policy Settings of ItemWithPolicy content type. It should have a custom Retention policy created and it will be exactly same as that of created in step 2.

Easy it is! I created multiple examples of this (multiple retention stages, policy with schedule, auditing policy). They can be downloaded from here.

Important Notes:
1.       I was able to declaratively create custom policies for the Site Content types only (content types present in Site Column gallery). Same was not true for the policies created directly on List Content Types. Information management policy settings page of such list content types gave me below error.  


[NullReferenceException: Object reference not set to an instance of an object.]
                                    Microsoft.Office.RecordsManagement.InformationPolicy.Policy.get_IsLocal() +47 Microsoft.Office.RecordsManagement.InformationPolicy.Policy.GetPolicy(SPContentType
                                    ct, Boolean overwriteStaleSiteCollectionPolicy) +116 Microsoft.Office.RecordsManagement.InformationPolicy.ApplicationPages.PolicyCtsUI.OnLoad(EventArgs
                                    e) +1636 System.Web.UI.Control.LoadRecursive() +65 System.Web.UI.Page.ProcessRequestMain(Boolean
                                    includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2427 

To me, this is a product bug. Even though I have not tried, I think creating List content type based policies programmatically should be possible.

2.       Declaratively policies can be created when Source of Retention for a list is set to Content Type (see figure 5).

Figure 5: List's Information management policy settings page


You will need to programmatically create custom policies when retention source is List or Folder. Declaratively there is no way. I am thinking that the reason is Content type does have xmldocument tag to declare custom policies but list schema does not have any such tags where policies can be defined.  
3.       This method also add event receivers and few columns to the content type. Do not remove them. I have seen SharePoint code (Mircosoft.Office.Policy.dll) in which I noticed that those columns are used. Same will be the case of event receivers.

That set! Hope this proves handy and a good read!

No comments:

Post a Comment