Skip to main content

Weblog Ton Stegeman [MVP]

Go Search
Home
  

ODC 2008
If you have a question or suggestion, please contact me through Windows Live Messenger.
My status: .

If I am not online, please send me an e-mail.
Weblog Ton Stegeman [MVP] > Posts > MOSS Custom policies part 3 - implementing the custom policy
MOSS Custom policies part 3 - implementing the custom policy

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.

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
    policytest1
  • Assign the content type to a document library
    policytest2
  • Upload a new document to the document library and set the title to “The truth on SharePoint development”
    policytest3
  • 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.
    policytest4
  • 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’.
    policytest5
  • 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.
    policytest6

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

Comments

Code?

Great article! Could you publish the ZIP file with the solution/code? Thanks, Jeroen
at 1/2/2008 4:13 PM

great job

nice work indead...
at 5/21/2008 9:00 AM

where is the source code zip file

where is the source code zip file
at 9/8/2008 6:41 PM

Is code missing from the article?

Hey Ton,

This is great article on custom policy and it covers all steps. I wondering if you have code available which you can post on the article to see everything on one place?
at 10/23/2008 11:08 AM

Re: MOSS Custom policies part 3 - implementing the custom policy

Great article and it is really helping in preparing for 70-542. If possible please provide the solution, that will be helpful.

Thanks
Aravind
http://aravindrises.blogspot.com/
at 2/24/2009 7:38 AM

where can I find the sample source code?

where can I find the sample source code?

thanks
at 7/31/2009 1:09 PM

zip file not found

zip file not found
at 9/16/2009 4:25 AM

Attached code???

Hello Ton! Where I can find a source code to this article? Thank you.
at 2/16/2010 1:04 AM

Good Stuff

After reading this article, I got an understanding about creating custom policy.

However, I did not see the attachment.

Thanks
Denny
at 3/1/2010 2:43 AM

Source Code

Hi, I am not able to find the code as you mentioned it is on the bottom of this file? Really appreciate if you can share that .zip file you mentioned.
at 3/26/2010 4:46 PM

Download

@Everybody:
Sorry, but the zip file with the code I used to have got lost at some point. Will try to recompile it.
Ton Stegeman at 3/27/2010 4:29 AM

Add Comment

Items on this list require content approval. Your submission will not appear in public views until approved by someone with proper rights. More information on content approval.

Title


Body *


Your city *


Type the name of the city you live in (making it easier to handle spam...)

CurrentDate *

Select the current date (see if this gives me fewer spam...)
Attachments

 Links

  SharePoint Object on CodePlex
  Screencast introducing SharePoint Objects
  Content by Type and Filter Web Parts on CodePlex
  Archive
  Archive (Calendar)

 My Latest Blog Posts

Scripting SharePoint 2007 setup: choices and conceptsUse SHIFT+ENTER to open the menu (new window).
Adventures in Visual Studio 2010: Migrate the Content By Type web part to SharePoint 2010Use SHIFT+ENTER to open the menu (new window).
Register SharePoint themes by using a featureUse SHIFT+ENTER to open the menu (new window).
SharePoint 2010 development on Windows 2008 Server R2 – Getting StartedUse SHIFT+ENTER to open the menu (new window).
New release SharePoint Objects: features and groupsUse SHIFT+ENTER to open the menu (new window).
Constructing the url to the SharePoint Edit Permissions pageUse SHIFT+ENTER to open the menu (new window).
Screencast: introduction to SharePoint ObjectsUse SHIFT+ENTER to open the menu (new window).
SharePoint 2007 and Reporting ServicesUse SHIFT+ENTER to open the menu (new window).
SharePoint Objects – Insight in usage of your SharePoint artifactsUse SHIFT+ENTER to open the menu (new window).
SharePoint 2007 Custom list schema and the Content Query Web PartUse SHIFT+ENTER to open the menu (new window).
SharePoint 2010 Silverlight Client Object Model – ExecuteQuery vs ExecuteQueryAsyncUse SHIFT+ENTER to open the menu (new window).
SharePoint 2010, the Client Object Models and Bing MapsUse SHIFT+ENTER to open the menu (new window).
Having fun with SharePoint 2010, Silverlight 3 and Bing MapsUse SHIFT+ENTER to open the menu (new window).
Connecting TFS 2010 projects to SharePoint sitesUse SHIFT+ENTER to open the menu (new window).
Adding a database to the SharePoint database Server using SPDatabaseUse SHIFT+ENTER to open the menu (new window).