Karine Bosch’s Blog

On SharePoint

Walkthrough 1 – Developing a Simple Event Receiver


The planets in our solar system have a unique name. This walkthrough demonstrates how you can check if the name of the planet entered by the user doesn’t already exist in the Planets list. If it doesn’t exist, the creation of the planet can be done. If the name is already entered, the creation must be cancelled.

Preparation

  1.  Create a custom list with the name Planet.
  2.  Change the name of the Title column into Planet. Change the number of maximum characters to 100.
  3. Add a column with the name Distance. This column will contain the distance to the sun and is of type Number.
  4. Add a column with the name Moons. This column will contain the number of moons and is a column of type Number. Set the number of decimal places to zero.
  5. Enter a first item with the following data:

a. Planet: Mars

b. Moons: 2

c. Distance: 229.000.000 (remark: this is the distance in kilometers)

Step 1 – Create the event handler

1. Open Visual Studio 2008 and create a class library project with the name UniverseEventHandlers.

2. Add a reference to the Microsoft.SharePoint.dll which can be found on the .NET tab under the label Windows SharePoint Services.

add-reference

 

3. Add the following using statement to the top of the class file:

using Microsoft.SharePoint;

4. Give your class the name PlanetItemEventReceiver and let it inherit from SPItemEventReceiver.

public class PlanetItemEventReceiver: SPItemEventReceiver 
{
   // add your code here
}

5. Because you want to check the name of the planet before the data is saved, you have to implement the ItemAdding event. Add therefore the following code:

public override void  ItemAdding(SPItemEventProperties properties)
{
    base.ItemAdding(properties);
}

6. The properties argument contains information about the context. It contains properties like:

a. ErrorMessage

b. Status

c. ListId

d. ListTitle

e. ListItem

f. ListItemId

g. BeforeProperties

h. AfterProperties

i. CurrentUserId

j. SiteId

k. WebUrl

7. The method must contain the code to check the existence of the planet. The best way to do this is by using the SPQuery object, which can execute CAML queries against a SharePoint list. When a planet with the same name is found, the ErrorMessage and Status properties need to be set and the action must be canceled:

public override void  ItemAdding(SPItemEventProperties properties)
{
    // get the name of the planet that needs to be saved
    string planet = properties.AfterProperties["Title"].ToString();
    using (SPWeb web = properties.OpenWeb())
    {
       // get the Planet list (will be queried for existing planet name)
       SPList list = web.Lists[properties.ListId];
 
       // build the query
       SPQuery query = new SPQuery();
       query.Query = string.Format("<Where><Eq><FieldRef Name=\"Title\" /><Value Type=\"Text\">{0}</Value></Eq></Where>", planet);
            
       // execute the query
       SPListItemCollection items = list.GetItems(query);
       if (items != null && items.Count > 0)
       {
           properties.ErrorMessage = string.Format(
             "The planet with the name {0} already exists.", planet);
           properties.Status = SPEventReceiverStatus.CancelWithError;
           properties.Cancel = true;
       }
    }
}

Notice the using construction in the code:

using (SPWeb web = properties.OpenWeb())
{
}

This is necessary to dispose correctly from the SPWeb instance to avoid memory leaks.

8. That’s it for the code. Build the project.

Step 2 – Create the feature

The assembly containing the event handlers must be deployed to the Global Assembly Cache.

The best way to deploy an event handler is by creating a feature that can be installed and activated to be used and can be deactivated and uninstalled if not needed anymore.

1. As you are going to deploy the dll into the Global Assembly Cache (GAC), you have to sign the assembly. In the Solution Explorer right-click the project and choose Properties. Activate the Signing tab and choose a key to sign the assembly.

2. Build the project.

3. Create the following folder structure in the Solution Explorer:

planet-event-handler

4. The feature.xml file is an XML file containing the definition of the feature. Important here to now is:

a. The feature id: must be a unique Guid.

b. The scope: this can be

i. Web: accessible thru the current site.

ii. Site: accessible thru the current site collection and its subsequent sites

iii. WebApplication: accessible thru the current IIS web applications, the site collections and the subsequent sites in it.

iv. Farm: accessible thru the farm.

<?xml version="1.0" encoding="utf-8" ?>
<Feature Id="{BDFA8DAD-F665-46a6-A4E4-87D012C0CEB2}"
    Title="Event Handlers - Walkthrough 1"
    Description="This feature demonstrates a simple event handler that checks the existence of a unique planet name."
    Scope="Web"
    Hidden="FALSE"
    xmlns="http://schemas.microsoft.com/sharepoint/">
 
  <ElementManifests>
    <ElementManifest Location="elements.xml" />
  </ElementManifests>
</Feature>

 

5. The elements.xml file contains the definition of the event handler. Important here to note is:

a. Receivers: element that contains one or more Receiver elements. The Receivers element must contains a ListTemplateId attribute (indicating a list template type) or a ListTemplateOwner attribute (indicating the id of the list when installed through a feature).

b. Receiver: Each type of event handler is contained within a Receiver element.

c. Type: type of the event handler.

d. Assembly: the strong name of the assembly.

e. Class: the namespace and class name of the event handler.

<Elements Id="{F5610B81-A2E2-4957-ABF2-B8ECCD765AF3}" 
          xmlns="http://schemas.microsoft.com/sharepoint/">
  <Receivers ListTemplateId="100">
    <Receiver>
      <Name>ItemAdding</Name>
      <Type>ItemAdding</Type>
      <SequenceNumber>1</SequenceNumber>
      <Assembly>UniverseEventHandlers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=841f382b41c47c60</Assembly>
      <Class>UniverseEventHandlers.PlanetItemEventReceiver</Class>
    </Receiver>
  </Receivers>
</Elements>

6. Add a last file to the root of the project and give it the name install.bat. This file will contain the necessary statements to install and activate the feature:

@SET TEMPLATEDIR="c:\program files\common files\microsoft shared\web server extensions\12\Template"
@SET STSADM="c:\program files\common files\microsoft shared\web server extensions\12\bin\stsadm"
@SET GACUTIL="c:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe"
 
Echo Installing the assembly in the GAC
%GACUTIL% -if bin\debug\UniverseEventHandlers.dll
 
Echo Copying files to TEMPLATE directory
xcopy /e /y TEMPLATE\* %TEMPLATEDIR%
 
Echo Installing Feature
%STSADM% -o installfeature -filename  “Planet Event Handler\feature.xml” -force
 
Echo Activating Feature
%STSADM% -o activatefeature -filename  “Planet Event Handler\feature.xml” –url “http://litwareinc.com” -force
 
IISRESET

Pay attention to the content of this file. The location of the GACUTIL utility depends on the Operating System you are running.

7. Save the project.

8. Open Windows Explorer and navigate to the location where you saved the project.

9. Double-click the install.bat file.

10. Open Internet explorer and navigate to the SharePoint site.

11. Try to add Mars again and note the error message on the beautiful error page.

17 Comments »

  1. Hi Karine,
    Good day to you.

    Could you please explain how to bind event receiver through feature to a custom list?
    I am able to bind the event receiver using the features, but the event receiver is available for the entire lists (Generic lists Listtemplate ID 100) in the web site where the feature is activated.
    Regards,
    Ajay

    Comment by Ajay | August 7, 2009 | Reply

  2. Hi Karine –

    Can you please explain where I can get the feature Id and Elements ID GUIDs for the xml files where do I pull this from?

    Also for the PublicKeyToken i’m assuming this comes from dropping the .dll file into the C:\Windows\Assembly to generate teh PublicKeyToken?

    Thanks for your help.

    JShidell

    Comment by JShidell | October 8, 2009 | Reply

  3. Hi JShidell,

    You can get the GUID from visual studio tools menu > create GUID, select “registry format” and click on “new GUID” button. Use copy button to copy the newly generated GUID. Generate seprate GUID for feature id and elements id.

    Use below command to get the public key token.
    sn -T

    Thanks,
    Pradeep

    Comment by Pradeep | December 4, 2009 | Reply

  4. One of the best tutorials on SharePoint development. Clear, simple, right to the points. Thanks.

    Comment by lin geng | April 6, 2011 | Reply

  5. […] copyright from: Karine Bosch’s Blog […]

    Pingback by Walkthrough 1 – Developing a Simple Event Receiver « Developer blogs | September 15, 2011 | Reply

  6. Hi Karine ,
    God blog.

    Regards,
    Shobhit

    Comment by shobhit | December 21, 2011 | Reply

  7. HI Karine,

    1. If I want to create Event Hanlder for IteamAddeing,ItemAdded,IteamDeleted, should i create seperate project for each IteamAddeing,ItemAdded,IteamDeleted.

    2. Once i deploy these Event Handlers, can i do modify these indivisual projects overriding with some other methods like ItemUpdating,ItemUpdated in place of original methods.

    Thanks,
    Syam,

    Comment by Syam | February 22, 2012 | Reply

  8. 1. You can use the same Visual Studio project and even the same class and define your event handlers in there.
    2. I don’t think I understand your question as these event handlers are overrides.

    Comment by Karine Bosch | February 28, 2012 | Reply

  9. Hi Karine,

    I had the need to implement this kind of feature in one of my sites!
    It’s a great work from you and a great tutorial.
    Unfortunattly it is not working for me.
    I am able to see the feature active in my site settings but I cannot related it to my list.
    I have created a planet list to performe your tutorial and followed it step by step. This is a custom list.
    But I am still able to insert planets with the same name.

    Do you have any ideia of what I might be missing?
    How do I make sure that I am binding the feature to a specific list?

    Regards,
    Aganju

    Comment by Aganju | August 1, 2012 | Reply

  10. Aganju, sorry for the late reply, I was on holiday.
    You relate the event receiver to your list in the elements.xml file (cfr step 2). You can also put a breakpoint in your event receiver to see if creating a new item hits the breakpoint.
    Karine

    Comment by Karine Bosch | August 12, 2012 | Reply

  11. Hi Karine, thanks for your reply!
    I am not really sure how can I do the debug with the breakpoint.
    I know I need to add a new project to this one. I also know I need to add a reference to Universe Handlers in the new project. But I cannot figure it out what type of project do I need to use, considering this is a Sharepoint specific thing and my Sharepoint-Visual Studio programming skills are not a big deal.

    If you could give some details so I could be able to put all the things together, I would really appreciate that.

    Thanks in advance!

    My best regards,
    Aganju

    Comment by Aganju | August 29, 2012 | Reply

    • In that case, the only thing I can advise you is a good SharePoint course 🙂

      Comment by Karine Bosch | January 25, 2013 | Reply

  12. How can I add .bat file? Please help

    Comment by Babbu | August 12, 2014 | Reply

  13. Hi Karine, Why are we building a SPQuery when we can use a camlquery ??

    Comment by Ravi | January 5, 2016 | Reply

    • Hi Ravi, to be honest, I don’t understand your question. Can you please give me a bit more details?
      Kind regards,
      Karine

      Comment by Karine Bosch | January 6, 2016 | Reply

      • // build the query
        SPQuery query = new SPQuery();
        query.Query = string.Format(“{0}”, planet);

        In the following lines of code, why are we using SPQuery when we can use a CamlQuery in the code, as we use it in CSOM.

        Sorry if my question is immature, i’m just a novice in the field. Thank You

        Comment by Ravi | January 6, 2016

      • Ah ok, I understand your question 🙂
        Well, event receivers, as described in this post, are written in server side object model, not in CSOM. Therefore, the use of SPQuery is more adequate.
        If are developing in CSOM, you have to develop a remote event receiver, and in that case you have to write CSOM and use a CamlQuery.
        Kind regards,
        Karine

        Comment by Karine Bosch | January 6, 2016


Leave a comment