Event handlers in WSS3 and MOSS 2007: some general notes and preventing a user update

Last week I was working on an event handler to prevent users from changing a value of a custom list item one an external service is busy processing some data.

Reading some information on event handlers I learned some important aspects about event handlers.

Deploy to the GAC: the assembly containing the event handler must be deployed to the Global Assembly Cache.

-Ed en -Ing events (asynchronous and synchronous events)
Event names ending on –ed like ItemUpdated, ItemDeleted and so on are called asynchronous events as they will execute after the action has been completed. At this stage you can no longer prevent something from being save or deleted.
The events ending in “ing” like ItemUpdating, ItemInserting and so on fire before the action is completed and are therefore called synchronous. In this case you can still intervene before the action is final.
The full list of available methods that can be overridden for SPItemEventReceiver can be found in the following MSDN article: http://msdn2.microsoft.com/en-us/library/ms437502.aspx

DisableEventFiring()
If you need to do an update to an item from within your event receiver you might end up in a recurring event being fired for the updates. To prevent this you can call DisableEventFiring() and then EnableEventFiring(). A small example for this:

public override void ItemUpdated(SPItemEventProperties properties)

        {

            //some handling here

            ListItem item = properties.ListItem;

            item["someproperty"] = "some value";

 

            this.DisableEventFiring();

            //save changes

            addedItem.Update();

            this.EnableEventFiring();

 

        }

When calling the Update method you might also consider using SystemUpdate() method which will do a SharePoint database updating without updating the time modified or versions of the item.

So now back to my event handler: I was looking for a way to know from within the event handler if it had been fired by a user action or by a system update. A system update is in my case a windows service opening the list item by using the object model.
As I’m using a schema.xml file to create the custom list I added a boolean field with the ReadOnly attribute set to true. This makes the custom field hidden in the edit form for the list item. When updating the item through the object model I do have access to the custom readonly field and can set its properties.

schema.xml snippet:

    ... ...

<Fields>

  <Field ID="{1FFDF566-D220-45e0-814D-34DB0E1A253D}" Name="Myreadonlyfield" StaticName="Myreadonlyfield" SourceID="http://schemas.microsoft.com/sharepoint/v3" Group="Groupname" DisplayName="SystemUpdate" Description="Hidden system field" Type="Boolean" ReadOnly="TRUE" Sealed="TRUE"></Field>

    </Fields>

       ...

</Fields>

My custom application sets the read only field to true before calling Update:

  item["fieldx"] = “some update”;

  item["SystemUpdate"] = true;

  item.Update();

As I’m using a synchronous event handler I can change the AfterProperties before these are saved into the database. This prevents the field from having a “true” value next time the item is updated.

public override void ItemUpdating(SPItemEventProperties properties)

       {

            bool isServiceUpdate = false;

            string modifiedStatus = Convert.ToString(properties.AfterProperties["somestatusfield"]);

 

            isServiceUpdate = Convert.ToBoolean(properties.AfterProperties["Myreadonlyfield"]);

 

            // Myreadonlyfield is always set to false except when the update comes from my custom application

            if (isServiceUpdate == false)

            {

 

                if (modifiedStatus.ToLower() == "invalid")

                {

                    properties.ErrorMessage = "This is an invalid choice...";

                    properties.Cancel = cancel;

                }

 

            }

            else

            {

                properties.AfterProperties["Myreadonlyfield"] = false;

            }

 

       }

I’m thinking maybe there is a much more efficient way of doing this but as I did not find any this way my solution. And what counts is it does the work.


And then here is a fantastic article series I found recently with very good information about event handlers in SharePoint 2007:
Brian Wilson - Event Handlers - Part 1: Everything you need to know about Microsoft Office SharePoint Server (MOSS) Event Handlers.

 

Technorati tags: , ,

 

Feedback

Posted on 05 February 2008 @ 11:46

Thanks for the DisableEventFiring() info this has resolved a nagging issue which I've had for a while. :)

Posted on 18 April 2008 @ 12:33

I have added the DisableEventFiring() line of code before I update this listItem and then I EnableEventFiring(). But I am still getting the same error. I dont think that these lines of code are working?

Posted on 17 June 2008 @ 09:47

How do i change the Version from the code?

Let's say user is check-in the file, and at the same time my checcking in event handler is executed.
now at the same time in the code. : i would like to change the version of the document. (minor to major version).
how to achive this?

I hope this needs to be done before :item.SystemUpdate(false);

Please post your comments:

Name:  
Email (optional): Your email address will not be posted.
URL (optional):
Comments: HTML will be ignored, URLs will be converted to hyperlinks  
Copyright © 2007 Katrien De Graeve.