Second Life of a Hungarian SharePoint Geek

February 15, 2010

My event receiver doesn’t fire

Filed under: Event receivers, Reflection, SharePoint — Tags: , , — Peter Holpar @ 00:59

On MSDN forums it’s a frequent complaint that somebody creates an event receiver but it does not fire. Based on my experience there is a few main types of this situation. In this post I try to help you to identify the issue and help to avoid or correct the problem.

The first question is why do you think the receiver does not fire? You might expect the receiver to do something (like create or delete a list item, send a mail, etc.), but it does not. Most time there is some kind of exception or a mistake in a condition that cause the code to do something different than you would like it to do.

But it does not mean automatically the receiver is not fired. So the first main type of “does not fire” is that where the receiver fires, but fails to do the expected activity, and it leads you to the incorrect assumption that it does not fire.

You can avoid this mistake by following the suggestions below.

Always use a try / catch / finally block within you receiver, and trace out the exceptions if happen. Also, it is good practice to trace out each entry and exit points in you receiver.

You should not reinvent the wheel so don’t want to log the trace information using your own methods, like simple opening a text file for write access and append the log info to the file. This can easily lead to file lock issues between receiver threads.

Instead, use the built-in .NET tracing infrastructure, like the Trace class from System.Diagnostics namespace namespace. You can use its methods (for example, TraceInformation) to create output from your event receiver.

  1. using System;
  2. using System.Web;
  3. using Microsoft.SharePoint;
  4. using System.Diagnostics;
  5.  
  6. namespace YourReceivers
  7. {
  8.     public class Receiver : SPItemEventReceiver
  9.     {
  10.         public override void ItemUpdated(SPItemEventProperties properties)
  11.         {
  12.             try
  13.             {
  14.                 Trace.TraceInformation("YourReceivers.Receiver ItemUpdated starting…");
  15.                 // do the job here
  16.             }
  17.             catch (Exception ex)
  18.             {
  19.                 Trace.TraceError("YourReceivers.Receiver ItemUpdated exception: {0}", ex.Message);
  20.             }
  21.             finally
  22.             {
  23.                 Trace.TraceInformation("YourReceivers.Receiver ItemUpdated finished");
  24.             }
  25.         }
  26.     }
  27. }

Trace every method entry and exit points as well as result of conditions.

To catch the output you can the use the WinDbg tool, or configure your web application to redirect trace output to a file (see <listeners> Element for <trace>  and the concepts of Trace Listeners). This way you get feedback if your receiver is called at all, and what happens under the hood without debugging, so this technique is useful either on production environment where you cannot use Visual Studio to debug the code.

You can even write your log messages to SharePoint Unified Logging System as described here:

The following post shows how to create a custom trace listener that writes to the ULS logs:

Of course, on the development environment you can get the most information by setting a breakpoint at the entry of the event receiver method and attaching the debugger to the worker process, so you can catch the event if it fired. One of my former posts shows you how to attach the debugger easier.

Second main group of “does not fire” issues is where the receiver is not registered correctly (for example, typo in class name or public key token), not registered at all, or the class you register cannot be loaded or does not implements the required methods or these methods are not public.

There are several ways that can be used to register or check the registration of an event receiver. For example, you can do that from your custom code (e.g. command line utility using the SPList.EventReceivers property,  and SPEventReceiverDefinition class) or from a 3rd party tool, like Patrick Tisseghem’s Event Handler Explorer.

The next code shows an example how to create a console application that checks the registered receiver classes and verifies the assemblies using Reflection:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.IO;
  5. using Microsoft.SharePoint;
  6. using Microsoft.SharePoint.Utilities;
  7.  
  8. namespace ReceiverCheck
  9. {
  10.     class Program
  11.     {
  12.         static void Main(string[] args)
  13.         {
  14.             if (args.Length == 1)
  15.             {
  16.                 try
  17.                 {
  18.                     String url = args[0];
  19.                     using (SPSite site = new SPSite(url))
  20.                     {
  21.                         using (SPWeb web = site.OpenWeb())
  22.                         {
  23.                             Program prog = new Program();
  24.                             prog.TestReceivers(web);
  25.                         }
  26.                     }
  27.                 }
  28.                 catch (Exception ex)
  29.                 {
  30.                     Console.WriteLine("ERROR: {0}", ex.Message);
  31.                 }
  32.             }
  33.             else
  34.             {
  35.                 Console.WriteLine("Usage: ReceiverCheck [URL of SharePoint site]");
  36.             }
  37.         }
  38.  
  39.         private void TestReceivers(SPWeb web)
  40.         {
  41.             int errorCount = 0;
  42.             int warningCount = 0;
  43.             foreach (SPList list in web.Lists)
  44.             {
  45.                 Console.WriteLine("INFO: Checking receivers on list: '{0}'", list.Title);
  46.                 bool foundReceiver = false;
  47.  
  48.                 List<String> definitions = new List<String>();
  49.  
  50.                 foreach (SPEventReceiverDefinition eventReceiver in list.EventReceivers)
  51.                 {
  52.                     SPEventReceiverType eventReceiverType = eventReceiver.Type;
  53.                     foundReceiver = true;
  54.                     Console.WriteLine("INFO: Checking receiver Id: '{0}', Name: '{1}'", eventReceiver.Id, eventReceiver.Name);
  55.  
  56.                     Assembly assembly = null;
  57.  
  58.                     if (String.IsNullOrEmpty(eventReceiver.Assembly))
  59.                     {
  60.                         Console.WriteLine("ERROR: The Assembly property is empty or null");
  61.                         errorCount++;
  62.                         break;
  63.                     }
  64.                     if (String.IsNullOrEmpty(eventReceiver.Class))
  65.                     {
  66.                         Console.WriteLine("ERROR: The Class property is empty or null");
  67.                         errorCount++;
  68.                         break;
  69.                     }
  70.                     if ((eventReceiverType.ToString().Substring(0, 4) != "Item") && (eventReceiverType != SPEventReceiverType.EmailReceived))
  71.                     {
  72.                         Console.WriteLine("WARNING: Checking event type: '{0}' is not supported by this tool", eventReceiverType);
  73.                         warningCount++;
  74.                         break;
  75.                     }
  76.  
  77.                     try
  78.                     {
  79.                         assembly = Assembly.Load(eventReceiver.Assembly);
  80.                     }
  81.                     catch (FileNotFoundException ex)
  82.                     {
  83.                         // general exception data
  84.                         Console.WriteLine("ERROR: Loading of assembly '{0}' is failed. An attempt to access a file that does not exist on disk or you have no access to fails.", eventReceiver.Assembly);
  85.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  86.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  87.                         // specific exception data
  88.                         Console.WriteLine("  File name: '{0}'", ex.FileName);
  89.                         Console.WriteLine("  Fusion log: '{0}'", ex.FusionLog);
  90.                         errorCount++;
  91.                         break;
  92.                     }
  93.                     catch (FileLoadException ex)
  94.                     {
  95.                         // general exception data
  96.                         Console.WriteLine("ERROR: Loading of assembly '{0}' is failed. The managed assembly is found but cannot be loaded.", eventReceiver.Assembly);
  97.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  98.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  99.                         // specific exception data
  100.                         Console.WriteLine("  File name: '{0}'", ex.FileName);
  101.                         Console.WriteLine("  Fusion log: '{0}'", ex.FusionLog);
  102.                         errorCount++;
  103.                         break;
  104.                     }
  105.                     catch (BadImageFormatException ex)
  106.                     {
  107.                         // general exception data
  108.                         Console.WriteLine("ERROR: Loading of assembly '{0}' is failed. The managed assembly is found but cannot be loaded.", eventReceiver.Assembly);
  109.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  110.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  111.                         // specific exception data
  112.                         Console.WriteLine("  File name: '{0}'", ex.FileName);
  113.                         Console.WriteLine("  Fusion log: '{0}'", ex.FusionLog);
  114.                         errorCount++;
  115.                         break;
  116.                     }
  117.                     catch (Exception ex)
  118.                     {
  119.                         // general exception data
  120.                         Console.WriteLine("ERROR: Loading of assembly '{0}' is failed", eventReceiver.Assembly);
  121.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  122.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  123.                         errorCount++;
  124.                         break;
  125.                     }
  126.  
  127.                     Console.WriteLine("INFO: Assembly '{0}' is loaded successfully", eventReceiver.Assembly);
  128.  
  129.                     Type type = null;
  130.                     try
  131.                     {
  132.                         type = assembly.GetType(eventReceiver.Class);
  133.                     }
  134.                     catch (FileNotFoundException ex)
  135.                     {
  136.                         // general exception data
  137.                         Console.WriteLine("ERROR: Loading of type {0} from a dependant assembly is failed. An attempt to access a file that does not exist on disk or you have no access to fails.", eventReceiver.Class);
  138.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  139.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  140.                         // specific exception data
  141.                         Console.WriteLine("  File name: '{0}'", ex.FileName);
  142.                         Console.WriteLine("  Fusion log: '{0}'", ex.FusionLog);
  143.                         errorCount++;
  144.                         break;
  145.                     }
  146.                     catch (FileLoadException ex)
  147.                     {
  148.                         // general exception data
  149.                         Console.WriteLine("ERROR: Loading of type {0} from a dependant assembly is failed. The managed assembly is found but cannot be loaded.", eventReceiver.Class);
  150.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  151.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  152.                         // specific exception data
  153.                         Console.WriteLine("  File name: '{0}'", ex.FileName);
  154.                         Console.WriteLine("  Fusion log: '{0}'", ex.FusionLog);
  155.                         errorCount++;
  156.                         break;
  157.                     }
  158.                     catch (BadImageFormatException ex)
  159.                     {
  160.                         // general exception data
  161.                         Console.WriteLine("ERROR: Loading of type {0} from a dependant assembly is failed. The managed assembly is found but cannot be loaded.", eventReceiver.Class);
  162.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  163.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  164.                         // specific exception data
  165.                         Console.WriteLine("  File name: '{0}'", ex.FileName);
  166.                         Console.WriteLine("  Fusion log: '{0}'", ex.FusionLog);
  167.                         errorCount++;
  168.                         break;
  169.                     }
  170.                     catch (Exception ex)
  171.                     {
  172.                         // general exception data
  173.                         Console.WriteLine("ERROR: Loading of type {0} is failed.", eventReceiver.Class);
  174.                         Console.WriteLine("  Exception type: '{0}'", ex.GetType());
  175.                         Console.WriteLine("  Exception message: '{0}'", ex.Message);
  176.                         errorCount++;
  177.                         break;
  178.                     }
  179.  
  180.                     if (type == null)
  181.                     {
  182.                         Console.WriteLine("ERROR: Loading of type {0} is failed.", eventReceiver.Class);
  183.                         errorCount++;
  184.                         break;
  185.                     }
  186.  
  187.                     Console.WriteLine("INFO: Type '{0}' is loaded successfully", eventReceiver.Class);
  188.  
  189.                     Type[] eventReceiverMethodParams = null;
  190.                     MethodInfo mi = null;
  191.                     String methodName = String.Empty;
  192.                     bool hadError = false;
  193.  
  194.                     if (eventReceiverType.ToString().Substring(0, 4) == "Item")
  195.                     {
  196.                         // checking base class
  197.                         if (!type.IsSubclassOf(typeof(SPItemEventReceiver)))
  198.                         {
  199.                             Console.WriteLine("ERROR: '{0}' class in assembly '{1}' must be subclass of SPItemEventReceiver class'",
  200.                                 eventReceiver.Class, eventReceiver.Assembly);
  201.                             hadError = true;
  202.                             errorCount++;
  203.                         }
  204.                         else
  205.                         {
  206.                             methodName = eventReceiverType.ToString();
  207.                             eventReceiverMethodParams = new Type[1] { typeof(SPItemEventProperties) };
  208.                             mi = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public, null, eventReceiverMethodParams, null);
  209.                         }
  210.                     }
  211.                     else if (eventReceiverType == SPEventReceiverType.EmailReceived)
  212.                     {
  213.                         // checking base class
  214.                         if (!type.IsSubclassOf(typeof(SPEmailEventReceiver)))
  215.                         {
  216.                             Console.WriteLine("ERROR: '{0}' class in assembly '{1}' must be subclass of SPEmailEventReceiver class'",
  217.                                 eventReceiver.Class, eventReceiver.Assembly);
  218.                             hadError = true;
  219.                             errorCount++;
  220.                         }
  221.                         else
  222.                         {
  223.                             methodName = "EmailReceived";
  224.                             eventReceiverMethodParams = new Type[3] { typeof(SPList), typeof(SPEmailMessage), typeof(String) };
  225.                             mi = type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public, null, eventReceiverMethodParams, null);
  226.                         }
  227.                     }
  228.                     if (!hadError)
  229.                     {
  230.                         if (mi == null)
  231.                         {
  232.                             Console.WriteLine("ERROR: '{0}' class in assembly '{1}' does not implement the method '{2}' required to handle event type '{3}'",
  233.                                 eventReceiver.Class, eventReceiver.Assembly, methodName, eventReceiverType);
  234.                             hadError = true;
  235.                             errorCount++;
  236.                         }
  237.                         else if (mi.DeclaringType != type)
  238.                         {
  239.                             Console.WriteLine("WARNING: Only a base class of the '{0}' class in assembly '{1}' does implement the method '{2}' to handle event type '{3}'. Probably receiver class does not override the method declaration of the base class.",
  240.                                 eventReceiver.Class, eventReceiver.Assembly, methodName, eventReceiverType);
  241.                             hadError = true;
  242.                             warningCount++;
  243.  
  244.                         }
  245.                         else
  246.                         {
  247.                             String definition = String.Format("{0};#{1}", type.FullName, eventReceiverType);
  248.                             if (definitions.Contains(definition))
  249.                             {
  250.                                 Console.WriteLine("WARNING: '{0}' class in assembly '{1}' is registered multiple times to the method '{2}' to handle event type '{3}' in the same list",
  251.                                     eventReceiver.Class, eventReceiver.Assembly, methodName, eventReceiverType);
  252.                                 warningCount++;
  253.                             }
  254.                             else
  255.                             {
  256.                                 Console.WriteLine("INFO: Checking '{0}' event type is successful", eventReceiverType);
  257.                                 definitions.Add(definition);
  258.                             }
  259.                         }
  260.                     }
  261.                 }
  262.  
  263.                 if (!foundReceiver)
  264.                 {
  265.                     Console.WriteLine("INFO: No receiver found in this list");
  266.                 }
  267.             }
  268.             Console.WriteLine("Error(s): {0}, Warning(s): {1}", errorCount, warningCount);
  269.         }
  270.     }
  271. }

Although the example above works only with the most common event types, it provides you a sample how to do more advanced checks for assemblies, classes and methods.

About these ads

8 Comments »

  1. Sometimes your event receiver is not firing properly. You may check a funny example of console application here http://malcan.com/EN/Lists/Tips%20and%20tricks/DispForm.aspx?ID=21

    Comment by Artur — May 23, 2010 @ 20:35

  2. Was very helpful post. I was able to troubleshoot my issue.

    Comment by Akhilesh — October 10, 2010 @ 02:38

  3. hi,

    Wanted to know if there is an event fired for SPFile.OpenBinary() call?

    Thanks

    Comment by arun — January 24, 2011 @ 06:29

    • Hi Arun,

      Typically there are no events for read operations. I don’t think one could capture the OpenBinary method call. You might be able to react for such read access events after enabling SharePoint audit log and check the log entries. I don’t know if that is suitable for you.

      Peter

      Comment by Peter Holpar — January 30, 2011 @ 20:34

  4. Hi,

    Your artical helped me to address issue regarding event receiver. Thanks a lot & keep up the good work.

    One more non sharepoint help i need from your side.
    Wordpress bydefault doesn’t allow to post long code snippet or it distort formatting of code.
    I want to know how you have used scrollable Textarea to paste long code snippets in your blog.. :)

    Thanks in advace :).

    Junaid

    Comment by junaid — October 20, 2011 @ 15:57

    • Thanks! I’m glad that you were able to solve your issue based on my writing.

      Actually, I use Windows Live Writer to publish my posts and code snippets are inserted through the Paste As Visual Studio Code plug-in. It is not perfect but the best I found for Live Writer. Hope it helps you.

      Comment by Peter Holpar — October 20, 2011 @ 16:31

  5. I ran into an odd ‘my event receiver doesn’t fire’ today. I have an event receiver that has handlers for ItemAdded, ItemUpdated and ItemDeleting in a SP 2010 farm. When I use the default SharePoint new item web form, it fires the event receiver, and I can use the debugger and step through the code.
    But when I create a new item from code, using the SPList.AddItem() and SPListItem.Update() methods, the event receiver does not appear to fire and the VS debugger does not break.
    Have run across this scenario before and do you know of a solution?

    Thanks,
    Scott

    Comment by smaple — November 23, 2011 @ 00:30

    • With additional testing, it looks like the problem is caused by the console program that creates the item exiting before the asynchronous event receiver handler (like ItemAdded) can execute. I am surprised that the the asynchronous event tries to piggy back onto the console program thread in this case. It also makes me wonder how item updates that occur on standard SharePoint forms avoid this problem and can I copy their method?
      I created a work around by having the main console program thread sleep for 30 seconds after it does an SPListItem.Update() call. It isn’t elegant, but it appears to work for now.

      Comment by smaple — November 23, 2011 @ 03:28


RSS feed for comments on this post. TrackBack URI

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

The Shocking Blue Green Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 53 other followers

%d bloggers like this: