Home > development, error, event handlers, MOSS, MS SharePoint Sever, sharepoint, sps, Uncategorized > Writing Event Handlers and Attaching/Detaching using Features

Writing Event Handlers and Attaching/Detaching using Features

 
In this post, I am going to write an event handler that:

  1. is triggered when an item is added to a document library (i.e. ItemAdded)
  2. sends an email to some email address notifying that an item has been added to the document library
  3. is deployed to a List using SharePoint Features

Okey, lets get started. Create a subsite under your site collection. In the subsite create a Document Library named AlertMe.

JumpStart – > JumpStartWeb -> AlertMe



homepage show




 

Create the Event Handler:

Go to Visual Studio 2008. Click File -> New -> Project …..and select Class Library:



create proj scr1




Give any name to your project e.g. “EventHandler.SharePoint.SendEmail.Feature”. This will also become the name of your namespace



enter proj name




Add the directives as shown below:



add reference 4 with all screen changes




Top four directives will already be there.

  1. “Microsoft.SharePoint” is to use sharepoint object model.
  2. “System.Reflection” is to get assembly information as we will need that to register the event handler with the document library.
  3. “Microsoft.SharePoint.Utilities” is to send email from SharePoint.

Your namespace name is the name you selected for your project. Rename Class1 to “EmailAlertsEventHandler” and make it to inherit from SPItemEventReceiver class. Rename the class in Solution Explorer window as well:






You might have noted that SPItemEventReceiver class name appears in black coloured font, that’s because we are missing a reference to Windows SharePoint Services.

Lets add the reference as shown below:



references




Right click “References” -> in the Solution Explorer window and click Add Reference.

Select Windows SharePoint Services as shown below:



select WSS




As soon as you will add this reference, Microsoft.SharePoint will appear under References and SPItemEventReceiver will change its colour to green which means that it is recognized as a class now.

If you want to see what SPItemEventReceiver contains, press Alt+Cntrl+j, Object Browser window will open. Expand Microsoft.SharePoint -> Microsoft.SharePoint -> SPItemEventReceiver. You will see all the methods in this class in the right hand pane. You will also see the ItemAdded method which we are going to use for our event handler.



obj browser




Alright, lets add a few methods to our class. As you will write “public override” and press space, intellisence will provide for you the list of all methods available in SPItemEventReceiver, as we saw in the Object Browser:



methods auto appear




Select ItemAdded from the list and enjoy the intelligence of VS, you will find a few things automatically done for you:



auto para and base call




Here is the  code for “EmailAlertsEventHandler.cs”:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Reflection;
using Microsoft.SharePoint.Utilities;

namespace EventHandler.SharePoint.SendEmail.Feature
{
    public class EmailAlertsEventHandler : SPItemEventReceiver
    {
        public override void ItemAdded(SPItemEventProperties properties)
        {
            base.ItemAdded(properties);
           
            SPListItem myItem = properties.ListItem;
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    using (SPSite site = new SPSite(properties.WebUrl))
                    {
                        using (SPWeb web = site.OpenWeb())
                        {
                            string emailSubject = "New Items Added to JumpStart";       
                            string emailBody = myItem.Name.ToString() +
                                " has been added to AlertMe Document Library for your review." + "\n" +
                                "\n" + "Thanks," + "\n" + "JumpStart EmailAlertsEventHandler!";
                            SPUtility.SendEmail(web, true, true, "rehman.gul@hotmail.com", emailSubject, emailBody);   
                        }
                    }
                });
            }
            catch (Exception ex)
            {
               
            }
        }
       
        public static void AddOrRemoveEventHandler(SPList list, bool doAdd)
        {
            Assembly asm = Assembly.GetExecutingAssembly();
            string className = typeof(EmailAlertsEventHandler).FullName;

            if (doAdd)
            {
                SPEventReceiverDefinition eventDef = list.EventReceivers.Add();
                eventDef.Type = SPEventReceiverType.ItemAdded;
                eventDef.Assembly = asm.FullName;
                eventDef.Class = className;
                eventDef.Name = className + "." + eventDef.Type.ToString();
                eventDef.SequenceNumber = 10001;
                eventDef.Data = null;
                eventDef.Update();
            }
            else
            {
                List<SPEventReceiverDefinition> eventsToDelete = new List<SPEventReceiverDefinition>();
                foreach (SPEventReceiverDefinition eventDef in list.EventReceivers)
                {
                    if (eventDef.Assembly == asm.FullName && eventDef.Class == className)
                    {
                        eventsToDelete.Add(eventDef);
                    }
                }
                foreach (SPEventReceiverDefinition eventDef in eventsToDelete)
                {
                    eventDef.Delete();
                }
            }
        }
    }
}

As you can see in the code above, there are only two functions ItemAdded and AddOrRemoveEventHandler. ItemAdded opens the web, gets the name of the item which invokes the event handler and sends an email to the specified address. AddOrRemoveEventHandler adds the event handler to the list or removes it, depending on the bool value “doAdd”.

Create the Feature Receiver:

Now how do we attach this Event Handler with a specific list. For that we said we will use Features, such that when the feature is activated, the event handler is attached to our list, and when the feature is deactivated, the event handler is detached from the list.

So, we have to write some code to capture Activate and Deactivate events of the feature. Right click on your project in the solution explorer -> Add -> Class ………..as shown below:



add new class




Select Class, give it a name like EmailAlertsFeatureInstaller:






Add the directives Microsoft.SharePoint, System.Reflection and Microsoft.SharePoint.Utilities on the top as shown below. Inherit the class EmailAlertsFeatureInstaller from SPFeatureReceiver. You can open the Object Browser to see all the methods available in SPFeatureReceiver..



new class with intelli and func




Before I move to add methods to this class, lemme explain what is SPFeatureReceiver doing here. Every feature can have four events i.e Feature Activation, Feature Deactivation, Feature Installation and Feature Uninstallation. Against these four events, SPFeatureReceiver class provides us with four methods respectively i.e. FeatureActivated, FeatureDeactivating, FeatureInstalled and FeatureUninstalling. These methods will be executed as the events take place. So, if we override these methods and put our custom code inside, our custom code will be executed whenever a feature is activated, deactivated, installed or uninstalled.

And thats what we wanted i.e. when a feature is Activated, our event handler gets attached to our AlertMe document library. And when the feature is Deactivated, our event handler is detached from our AlertMe document library.

Here is the full code for EmailAlertsFeatureInstaller.cs:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Reflection;
using Microsoft.SharePoint.Utilities;

namespace EventHandler.SharePoint.SendEmail.Feature
{
    class EmailAlertsFeatureInstaller : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb web = (SPWeb)properties.Feature.Parent)
                {
                        SPList list = web.Lists["AlertMe"];
                        EmailAlertsEventHandler.AddOrRemoveEventHandler(list, true);
                }
             });
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPWeb web = (SPWeb)properties.Feature.Parent)
                {
                    List<SPList> webLists = new List<SPList>();
                    foreach (SPList list in web.Lists)
                    {
                        webLists.Add(list);
                    }

                    foreach (SPList list in webLists)
                    {
                        EmailAlertsEventHandler.AddOrRemoveEventHandler(list, false);
                    }
                }
            });
        }

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
        }
       
    }
}


As you can see we have overriden only two methods of SPFeatureReceiver class i.e. FeatureActivated and FeatureDeactivating. On FeatureActivated we get to our list AlertMe and call AddOrRemoverEventHandler with a ‘true’ value i.e. attach the event handler. On FeatureDeactivating we iterate through all the lists and call AddOrRemoveEventHandler with a ‘false’ value i.e. detach the event handler.

Also, you can see above in the code that we have added FeatureInstalled and FeatureUninstalling methods though there is no functionality added to them. This is mandatory, if you will not add these methods you will receive an error message because these are abstract members of SPFeatureReceiver class and we must implement them in our class.  

Alright we are ready to build our project. Try building and it should work.

Put your assembly in the GAC:

Now lets put our assembly (dll) in Global Assembly Cache (GAC) so that it is available to SharePoint. For that we have to strongly name our assembly as it will be placed in a shared location (GAC).

To strongly name your assembly, right click on your project in Solution Explorer window and click Properties:



sign 1




Select Signing at the bottom and fill the check box saying “Sign the assembly”. In “Choose a stong name key file” drop down, select <New…>. In “Key file name” text box, give name of your project (assembly) like “EventHandler.SharePoint.SendEmail.Feature”……..click OK…….as shown below:



sign 2




You will that a file named “EventHandler.SharePoint.SendEmail.Feature.snk” has been added to our project. If you click the file, you will see something similar:



key code




Now our assembly is ready to go to GAC. Go to your working directory on the file system, move to \bin\Debug folder e.g.

C:\Work\EventHandler.SharePoint.SendEmail.Feature\EventHandler.SharePoint.SendEmail.Feature\
bin\Debug

Here you will find your assembly i.e. EventHandler.SharePoint.SendEmail.Feature.dll

Open GAC i.e. c:\windows\assembly and drag and drop your dll in the GAC as shown below:



GAC




Do an IISRESET.

Create the Feature:

Now comes the second part of our project i.e. to create the Feature. Remember, we have created a Feature Receiver until now, Feature itself is still to be created.

All Features in SharePoint lies in 12 hive under Features directory:

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES

Browse through a few Feature directories and you will find that all of them have a feature.xml file……and some will also have an elements.xml.

Lets create a Feature of our own. Create a folder under Features directory and name it EventHandler.SharePoint.SendEmail.Feature………..could be any name..






Go inside the folder, right click -> New -> Text Document and rename the text document as feature.xml file. Create another file in the same manner and save it as elements.xml:



feature start




Right click feature.xml file and Open With -> Notepad. Paste the following xml in the file and save:


<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="F2F6FE98-7A4C-4db7-B1E3-BC9C6E5CC9D7"
          Title="EventHandler SharePoint SendEmail Feature"
          Description="Email Alerts for AlertMe Library"
          Version="1.0.0.0"
          Hidden="FALSE"
          Scope="Web"
          DefaultResourceFile="core"
          ReceiverAssembly="EventHandler.SharePoint.SendEmail.Feature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=74b4a55dc039bd07"
          ReceiverClass="EventHandler.SharePoint.SendEmail.Feature.EmailAlertsFeatureInstaller"
          xmlns="http://schemas.microsoft.com/sharepoint/">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>
  </ElementManifests>
</Feature>

Note that you have to be careful about four items in this xml. Feature Id, ReceiverAssembly, PublicKeyToken and ReceiverClass. They could be different in your case, so use the ones that you have.

For PublikKeyToken, go to GAC, take properties of your assembly and copy/paste into your feature.xml.

Feature Id is just a GUID. Here is how you can get one of your own:

Go to Visual Studio, click Tools ->Create GUID. If Create GUID option is greyed out, click Tools -> External Tools. Make the following settings as shown in the figure below and click OK. This will enable Create GUID option.

“Initial directory” in VS 2008 will be
C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\



generate GUID




Click Create GUID and you will receive it as under:






Click copy and paste it into Feature Id in feature.xml as shown above.

Open elements.xml and paste the following xml into it:


<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
</Elements>

Install and Activate the Feature:

Alright, coool, our feature is ready to be installed now.

Open the command prompt and move to the Features directory. Enter the following command:

stsadm -o installfeature -name EventHandler.SharePoint.SendEmail.Feature




feature install scr




After you have received the “Operation completed successfully” message, navigate to your site in SharePoint. In my case the heirarchy was JumpStart -> JumpStartWeb -> AlertMe.

So, I’ll move to JumpStartWeb -> Site Actions -> Site Settings ->  under Site Administration click Site Features. You will see your feature available there as shown below:






Click Activate button in front of your feature to Activate the feature:



feature scr activate




Test your Event Handler:

Go to your document library, in my case it is AlertMe and upload a document:






As soon as you upload the file, you should receive an email to the address specified in your event handler:






Hope this helps–

Update: If you wish to deploy this event handler using solution packages, look here.

Advertisements
  1. November 17, 2009 at 2:23 pm

    Great post, would you be interested in cross posting this on the SharePointDevWiki.com and linking back to this one?

  2. November 17, 2009 at 2:58 pm

    Thanks Jeremy,

    Yeah should be alright!

    • jthake
      November 17, 2009 at 3:02 pm

      SPDevWiki can import from a .doc file into a page you add and save. so you can get all the screenshots etc. in in one go.

  3. November 24, 2009 at 3:39 pm

    Thanks for the great post. This is the first one I’ve come across on this subject that was thorough and actually worked (without typos) the first time! 🙂

    Since the “FeatureActivated” method has a hard coded List Name “AlertMe” in the code, would it be best to add the name of the list this feature is targeted to as part of the dll name? Potentially, i could have many feature dll’s in my GAC, but it could be very confusing to know what dll does what. What would you suggest is the best practice for naming dlls?

    Thanks again for your post.

  4. November 24, 2009 at 11:09 pm

    Thanks Rick,

    Usually the DLLs are named such that you are able to get a quick idea of what it is supposed to do. I wont recommed to add tokens to the name that represent content utilized within the DLL. If you modify the FeatureActivated given above, you could actually run this for all of the lists in your web, and in that case it would be impossible to give it a content based name.

    In a real world, you will usually do:

    CompanyName.ProductName.WhatItDoes.dll OR

    ClientName.SharePoint.WhatItDoes.dll

    Hope this helps–

  5. saritha
    December 2, 2009 at 9:53 pm

    Hi Rehmangul -Excellent post ,Very clear from point to point,Can you please help me how to acheive this event hander for setting item level permissions for sharepoint list based on login user and related to his groups.Thanks

    Saritha

    • December 4, 2009 at 12:29 am

      Hi Saritha,

      Here is how you can set item level permissions. This is just to give you an idea, if you copy/paste, please look for typos:

      public string ItemLevelPermissions(string SiteAddress)
      
      {
      
              string ReturnResult = "";
      
              try
      
              {
                  SPSecurity.RunWithElevatedPrivileges(delegate()
                  {               
                     using (SPSite WebApp = new SPSite(SiteAddressHere))
                     {
      
                         using (SPWeb Site = WebApp.OpenWeb())
                         {
      
                            SPList list = Site.Lists["MyDocLib"];
      
                            SPListItem item = list.Items[0];
      
                            SPRoleDefinition RoleDefinition = Site.RoleDefinitions.GetByType(SPRoleType.Contributor);
      
                            SPRoleAssignment RoleAssignment = new SPRoleAssignment("<DomainNameHere>\\<UserNameHere>", "EmailAddressHere", "GiveNameHere", "GiveNotesHere");
      
                            RoleAssignment.RoleDefinitionBindings.Add(RoleDefinition);
      
                            if(!item.HasUniqueRoleAssignments)
      
                            {
      
                               item.BreakRoleInheritance(true);               
      
                            }
      
                           item.RoleAssignments.Add(RoleAssignment);
      
                           item.Update();
      
                        }
                     }
                 });
              }
              catch (Exception ex)
      
              {
      
                  ReturnResult += "Sorry the permissions could not be set for the item due to the following exception: " + ex.Message;
      
              }
      
              return ReturnResult;
      }
      
  6. Gautam
    December 9, 2009 at 12:29 pm

    Hi,
    This same functionality is also available through the built-in SharePoint 2007 Alerts for Lists and Document Libraries.

    Can u tell me the difference between the in-built functionality and this post and which option is better?

    Thanks.

  7. December 9, 2009 at 3:02 pm

    Hi Gautam,

    The purpose here is to show how you can write Event Handler features in sharepoint. “Sending Email” is just a sample task that you may want to execute on ItemAdded event. For instance, I could have set a MetaData value for the item that is just added. Its by chance that “Sending Email” here resembles sharepoint alerts, otherwise its not the actual purpose of the post.

    I hope you got the point!

    Cheers,

    • Gautam
      December 10, 2009 at 1:10 pm

      Thanks for ur reply.
      This is a great and a very useful post.

      Regards.

      • December 10, 2009 at 10:34 pm

        Thanks Gautam!

  8. December 16, 2009 at 7:51 am

    Thank you Rheman Gul for your post, I have sent you an email regarding an issue with an event handler that I am writing, did you have a chance to see it?
    Greetings,

  9. December 17, 2009 at 1:54 am

    Thanks Yasser, I’ll have a look and let you know if I am able to come up with somethintg helpful.

    Cheers,

  10. JC
    January 27, 2010 at 9:13 am

    Thank for this very useful post !
    I’ve got a question, how do you reference another event, for instance ItemDeleting (or Deleted) in the addorremoveeventhandler void? i tried to add a “SPEventReceiverDefinition eventDef2 = list.EventReceivers.Add(); etc. ” block
    to reference the deleting event in the assembly but it doesn’t seems to work
    thanx

    • April 12, 2010 at 2:13 am

      what is the error message that you get?

  11. Rajesh Rathi
    March 1, 2010 at 2:03 pm

    I am looking for an event handler, which should allow only creator of a list item to update one field named as “ISSUE STATUS” as CLOSED. any one else can change the filed to any value other then CLOSED, but only creator should be able to change value to close it.

    • April 12, 2010 at 2:12 am

      cant do out of the box, custom code fired on an update event.

  12. Andrey
    April 8, 2010 at 12:53 pm

    Hello, great thanks for the post. I’ve got a question.
    Your code works perfectly, but i’d like to do it without hardcoding the list name – for example activate it in the each doclibrary of the website. But I get the error “Collection was modified; enumeration operation may not execute”.
    How can I debug the activating process of my feature?
    Thanks

  13. April 12, 2010 at 2:08 am

    Hi Andrey, are you changing contents of a list during enumeration, if yes, it might cause this problem of “Collection was modified………….”. Keep enumeration and modification separate.

  14. Suryakant
    May 15, 2010 at 6:01 am

    Hi
    I have created one email custom event handler its fires when I sent mail from same computer outlook express.. but not fires if I sent mail from any outside mail server..
    Please give me any idea If U have ..thanks..!

  15. Suryakant
    May 15, 2010 at 6:14 am

    Some details for above comment..Mail is receiving to drop folder in both cases i.e. when sent from same outlook express as well as external mail server.. But only mail which is from outlook express get picked up and sent to list other mail not goes
    to list

  16. arun
    January 30, 2011 at 11:56 am

    hi,

    Is there an event triggered while opening a document, could not find one under item events, if not can you suggest a way for this scenario?

    thanks

  17. Zee
    March 17, 2011 at 1:28 pm

    Great, article, the best one I’ve came across online. Thanks.

  18. vergil
    May 3, 2011 at 11:00 am

    Very useful article. Great work.

  19. Sandesh
    September 8, 2011 at 5:41 am

    when i am activating feature following error is display

    The method or operation is not implemented.

    • September 8, 2011 at 5:54 am

      check the spellings of the receiver class:

      ReceiverClass=”Namespace.RecevierClass”

      in your feature xml.

      • Sandesh
        September 8, 2011 at 7:07 am

        I have checked all spellings its corrected,

        Right now i am activated feature following error is display

        Failed to create feature receiver object from assembly “EventHandler.SharePoint.SendEmail.Feature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9ad4fd4cf18c6d30”, type “EventHandler.SharePoint.SendEmail.Feature.EmailAlertsFeatureInstaller” for feature a75cb419-6be4-41c6-b1c5-c4635f514eec: System.ArgumentNullException: Value cannot be null.
        Parameter name: type
        at System.Activator.CreateInstance(Type type, Boolean nonPublic)
        at System.Activator.CreateInstance(Type type)
        at Microsoft.SharePoint.Administration.SPFeatureDefinition.get_ReceiverObject()

      • September 9, 2011 at 4:34 am

        Sounds funny though but at least in one scenario IISRESET fixed the error for me.

  20. Hoa NGO
    February 29, 2012 at 7:33 pm

    Hi Rehmangul,
    Thank you for the great post. I am a newbie in SharePoint Programming and follow your great description to create the EventHandler. I could get it running because of 2 problems:
    1/- I could not find the reference Windows@SharePoint@Services in reference list. I have SP Server 2010 and VS2010 on Win7 64bit PC, I use only the reference Microsoft.SharePoint and even without the Services reference, the project still built. Is it because the reference I already includes the missing Services?
    2/- Then I moved on with that assumption and built and then sign the snk key, but could not drop EventHandler.SharePoint.SendEmail.Feature.dll into my GAC. After I dropped it there I did not see any error popped up but the assembly never showed up as expected. What did I do wrong there?
    Thank you very much for your help
    Hoa Ngo

  21. Hoa NGO
    March 2, 2012 at 9:34 pm

    Hi Rehmangul,
    I got the feature built and deployed to my local SPServe, this is great. But the call
    SPUtility.SendEmail(web, true, true, “myEmail@xyz.com”, emailSubject, emailBody);
    returned a FALSE value.
    Can you suggest where I can verify my Email settings?
    Thank you

  22. Saran
    May 24, 2012 at 11:25 am

    Hi Rehman,
    Excellant Post !!!. This is the actual post which i was googling for sometime.
    Could you clarify my below doubts ?

    1. Do we have any change in the above said approach when we develop the event receiver and feature using MS VS 2010 ?
    2. I want to keep the list name in a config file using the above approach. Is it possible ?

    Thanks in advance !

  23. Thirupathi
    September 28, 2012 at 7:31 pm

    I tried creating the solution as explained and got struck at the step: Put your assembly in the GAC. After performing the steps described to create the file with .snk extension, I could not see my .dll file in the /bin/Debug folder. I am using MS Visual Studio 2008 for the development. Could anybody suggest where I might have gobne wrong…? Please..

    Thanks
    Thirupathi Uppu

    • October 1, 2012 at 11:41 am

      Build the solution. Cntrl + Shift + B ………or right click solution and Build…….after that look into the bin\Debug folder…..

  1. November 25, 2009 at 3:28 am
  2. December 2, 2009 at 1:42 pm
  3. January 6, 2010 at 6:24 am
  4. January 9, 2010 at 7:11 am

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: