SharePoint Events – Setting a Column Value in the ItemUpdating Event

I was recently tasked to automatically set a document ID value in a SharePoint 2007 document library. (In SharePoint 2010, an excellent document ID feature is included out of the box)  I figured it would be easy since SharePoint supports calculated columns.  However, I needed to be able to insert the document ID value into a Word document as a field.  Sharepoint does not include calculated fields as part of the document metadata so using calculated columns was not a good solution for me.  An event handler seemed like the best way to go.

There are a lot of actions a user could take that should trigger my code.  See my previous post SharePoint Event Handling – When do events fire?  I needed my code to be triggered no matter which action the user took.  The best approach I found was to use the ItemUpdating event and then force ItemUpdating to be called by triggering an update in the ItemAdded event.

My first attempt at the code looked like this:

public override void ItemAdded(SPItemEventProperties properties)
{
    base.ItemAdded(properties);
    //Make sure the ItemUpdating method gets called even when using SaveAs from MSWord.
    properties.ListItem.SystemUpdate(false);
}

public override void ItemUpdating(SPItemEventProperties properties)
{
	try
	{
		string newFieldValue = GetNewFieldValue();
		object oldFieldValue = properties.AfterProperties[COLUMN_NAME];
		if (oldFieldValue == null || oldFieldValue.ToString() != newFieldValue)
		{
			properties.AfterProperties[COLUMN_NAME] = newFieldValue;
		}
	}
	catch
	{
	    //Log the error, or take another appropriate action.
	}
	finally
	{
		base.ItemUpdating(properties);
	}
}

I found that there were circumstances when the column value would not get set or would be cleared and I would get the default value for the column instead.  After hours of debugging and testing, I discovered that it was only clearing my column when ItemUpdating was triggered and the value of my column had already been set properly and hadn’t changed.  So I made the obvious change and removed the piece of my code that skips explicitly setting the column value if it has already been set.

public override void ItemUpdating(SPItemEventProperties properties)
{
	try
	{
		string newFieldValue = GetNewFieldValue();
		object oldFieldValue = properties.AfterProperties[COLUMN_NAME];
		//if (oldFieldValue == null || oldFieldValue.ToString() != newFieldValue)
		//{
			properties.AfterProperties[COLUMN_NAME] = newFieldValue;
		//}
	}
	catch
	{
	    //Log the error, or take another appropriate action.
	}
	finally
	{
		base.ItemUpdating(properties);
	}
}

This fixed the problem … Now I needed to figure out why.  I stepped through the code with the VS debugger and found that the properties.AfterProperties[COLUMN_NAME] had the correct value for the entire method, but some time after the ItemUpdating method finished  the value was cleared, unless I had explicitly set the value during that pass.  I did some research, but wasn’t able to find a reasonable explanation for this behaviour.  I will add to this post once I find one.  In the meantime, I hope this quick fix will help some of you avoid the same type of problem.

Advertisements

9 Comments

  1. vijay
    Posted March 23, 2011 at 4:49 am | Permalink | Reply

    hi,

    I tried the above solution which dint help, im trying to set value for a Boolean field, and could see value isnt modified.

    • DeanV at MikeTango
      Posted March 23, 2011 at 10:38 am | Permalink | Reply

      The solution works when I try it using Boolean values. Is your event handler firing at all? Try putting a breakpoint at the start of the event method, attaching to the w3wp process and see if it gets hit. If the breakpoint doesn’t get hit, chances are good that your event handler is not wired up properly.

  2. Slawekba
    Posted July 21, 2011 at 10:54 am | Permalink | Reply

    Hello Did you solve a problem? Could you share the code for GetNewFieldValue()? It seams that the code within the GetNewFieldValue() is the curcial part of the code. In case user intentionally remove the value from the COLUMN_NAME field the system is not able to recognized if it was manged by user or by system.
    Please, let me know what is unde the GetNewFieldValue(). Thanks in advance.

    • DeanV at MikeTango
      Posted July 21, 2011 at 11:30 am | Permalink | Reply

      Slawekba,

      I wrote the sample in this post to be pretty generic. The function GetNewFieldValue() just creates the new value that you want to set the column to. It could be setting the day of the week, or the next number from a counter, or a username, or anything else really. If it helps to understand the code more easily, you can just replace the GetNewFieldValue() method with a string like “YourValueGoesHere” and the rest of the code will work the same way.
      Recognizing whether or not a field was deleted by a user or by the system is a completely different problem, and too complex to get into in the comments section, but I’ll try and write a new post about it soon.

      Hope this helps.

  3. Slawekba
    Posted July 21, 2011 at 11:13 am | Permalink | Reply

    Finally I use following code. So far it’s working.
    Regardless if you know how to get the original value form Request.QueryString or any other way how to take independently the value for field, be so kind and share this information.

    string subjectBefore = properties.BeforeProperties[“To”] as string;
    string subjectAfter = properties.AfterProperties[“To”] as string;

    try
    {
    string oldFieldValue = properties.BeforeProperties[“To”] as string;
    string newFieldValue = properties.AfterProperties[“To”] as string;

    if(newFieldValue==null)
    {
    newFieldValue = oldFieldValue;
    }

    if (oldFieldValue == null || oldFieldValue != newFieldValue)
    {
    properties.AfterProperties[“To”] = newFieldValue;
    }
    }
    catch
    {
    //Log the error, or take another appropriate action.
    }
    finally
    {
    base.ItemUpdating(properties);
    }

    • DeanV at MikeTango
      Posted July 21, 2011 at 11:56 am | Permalink | Reply

      I’m not sure what you mean by ‘take independently the value for field’ If you want to look at the value for the field without examining the Before/After Properties, you could always get the SPListItem independently by querying the SPList directly.
      From your code it looks like you are trying to prevent someone changing the “To” column in your list. I would normally just cancel the update to give the user some feedback that the change he made was not valid. If that isn’t an option in your case, all you really need to do is:

      //Put this inside the try block, of course
      string beforeValue = properties.BeforeProperties[“To”] as string
      string afterValue = properties.AfterProperties[“To”] as string

      if (beforeValue != afterValue)
      {
      properties.AfterProperties[“To”] = beforeValue;
      }

  4. Slawekba
    Posted July 22, 2011 at 6:04 am | Permalink | Reply

    I follow your post. I get the same problem as you: in the ItemUpdating Sharepint system “do” something with field values. As far as we are able to discover that field value from AfterProperties/ BeforeProperties was set up on NULL we can do some work around – what was presented in your code by try/catch. I went deeper and investigated that the issue appears for field which had a value but in the item was updated and the field was not updated by the user – user is able to clear the field so the field is set to string.empty. So as far as we discover that the field is equal null, we are able to make some work around as was presented in my code. It seam that I update the value which was provided by user, but as user is not able set the value on null – user is able to set it as empty string. So I assume that my proposition is operational as long as the field value is set up by the system on null. In case system set the value on empty string it is also possible to do some work around but only when the field is obligatory field. I skeep the code because the reader could do it by him/herself.
    The real problem appears once the value is not set on null but on empty string. It means that we need to get the right value not form the AfterProperties/ BeforeProperties/ Item (they are not reliable as long as system do something by itself with no user action) but somehow outside of the event mechanism. It seams that the best way is to take if from HTTPContext – if anybody have an idea how to get the value from httpcontex, please let me know.

  5. Ashwin
    Posted February 19, 2012 at 6:09 pm | Permalink | Reply

    I’ve written a console app that searches items in a SP document library (MOSS 2007) for a specific condition and updates the value in a column for each item that meets the criterion. I run the console app as a domain/SP admin and on the front-end SP server, so there is no question of security, rights, etc. The code in question is as follows:

    item[“some column”] = “some value”;
    item.Update();

    1 2/19/2012 10:23:47 AM ItemUpdating http://server/sites/web/Shared Documents/Document01.pdf > http://server/sites/web/Shared Documents/Document01.pdf
    1 2/19/2012 10:23:47 AM ItemUpdating SetID: Key=shared documents/Document01.pdf value=

    0002871
    634652438271779415
    false
    false

    10 2/19/2012 10:23:47 AM ItemUpdated SetValue: 0002326

    Examining the item’s column value, I can see the column value has been updated. But all this output is making me wonder if there are any adverse side effects.

  6. Posted July 11, 2013 at 5:48 am | Permalink | Reply

    Anyone who has a little bit of SharePoint development knowledge can easily understand and implement this code as a reference for Setting a Column Value in the ItemUpdating event in the project.

2 Trackbacks

  1. […] SharePoint Events – Setting a Column Value in the ItemUpdating Event […]

  2. […] work. I did a spot of Googling about, and found the chaps at Tango Technology who had written a very simple solution to it. But – it wouldn’t work for me. I knew the event was firing – but no matter […]

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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 )

Google+ photo

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

Connecting to %s

%d bloggers like this: