How to: Write and Debug a Project Server Event Handler

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Each business object in Microsoft Office Project Server 2007 has a corresponding base abstract class. When you write an event handler for an event from a business object, you derive the event handler class from the corresponding base abstract class. For example, an event handler class for the Project business object derives from ProjectEventReceiver; an event handler class for the Resource business object derives from ResourceEventReceiver; and so forth.

The base abstract classes are defined in the Microsoft.Office.Project.Server.Events name space. The Microsoft.Office.Project.Server.Events.Receivers.dll assembly is in the global assembly cache on the Project Server computer.

Important noteImportant

You can develop a Project Server event handler either on the local Project Server computer or on a remote computer. In either case, you should use only a test Project Server installation, not a production server, to develop, test, and debug event handlers.

You can use Microsoft Visual Studio 2005 or a text editor and Command Prompt window to write the code and compile the event handler assembly. The examples are for Microsoft Visual C#. The process is easier in Visual Studio because Microsoft IntelliSense shows the event handler base classes and helps complete the code framework for method overrides. This article shows how to develop the event handler with Visual Studio and also provides an example compiler command line.

To deploy the event handler to the Project Server computer, you can use XCopy deployment to a special event handler directory or register the event handler assembly in the global assembly cache. This article describes both procedures.

For information about event architecture, processes, and how to find event argument properties, see Project Server Events.

For help in testing a Project Server event handler, see the Debugging an Event Handler section. For the complete code sample, see the Example section.

NoteNote

Because Microsoft Office Project Professional 2007 and Project Web Access sometimes call private PSI methods in the PWA and WinProj Web services, they do not always trigger the same events that the public PSI methods do. When you develop event handlers, test whether actions in Project Professional and Project Web Access, as well as in third-party applications that use the PSI, trigger event handlers as you expect.

To use a DataSet object in an event handler, you must set a reference to the Microsoft.Office.Project.Schema.dll assembly. The Microsoft.Office.Project.Server.Schema namespace includes the necessary class definitions such as ProjectDataSet and ResourceDataSet. You can copy the schema assembly from C:\WINDOWS\assembly\GAC_MSIL\Microsoft.Office.Project.Schema\12.0.0.0\71e9bce111e9429c, if you first run the following command.

regsvr32 /u C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\shfusion.dll

After you copy the assembly, run the regsvr32.exe command again without the /u option, to reset the Windows Explorer view of the assembly directory. For a code example of an event handler that uses a DataSet object, see Using Datasets in Event Handlers in Getting Started with a New Platform for Developers.

Developing an Event Handler

To develop an event handler, use the following procedures:

  1. Create a class library project and set references.

  2. Develop the event handler code, and compile the assembly.

  3. Deploy the event handler assembly to the Project Server computer.

  4. Register the event handler with Project Server using Project Web Access.

  5. Test the event handler.

  6. Debug the event handler.

Procedure 1. To create a class library project and set references:

  1. If you are developing on a separate computer, copy the Microsoft.Office.Project.Server.Events.Receivers.dll assembly from the [Program Files]\Microsoft Office Servers\12.0\Bin directory on the Project Server computer to a convenient directory on your development computer. You use the Microsoft.Office.Project.Server.Events namespace for the base event receiver classes of each Project business object. When you try to add a reference to some Project Server assemblies in Visual Studio, you may not see them on the .NET tab in the Add Reference dialog box.

    Note

    You can also unregister shfusion.dll to disable the Assembly Cache Viewer and copy assemblies from the [Windows]\assembly global assembly cache. Use the following command: Regsvr32 /u [Windows]\Microsoft.NET\Framework\v2.0.50727\shfusion.dll. Unregistering shfusion.dll is a workaround. Visual Studio currently does not show assemblies in the global assembly cache. You should re-register shfusion.dll when you have completed compiling the application, or have copied the assemblies you need to your development computer.

  2. In Visual Studio, create a new project of type Class Library; for example, name the project TestEventHandler. For a Visual C# project, rename the Class1.cs file if you want, for example MyEventHandler.cs.

  3. In the Add Reference dialog box of Visual Studio Solution Explorer, click the Browse tab, browse to theMicrosoft.Office.Project.Server.Events.Receivers.dll assembly, and then click OK.

  4. Similarly, set a reference to the Microsoft.Office.Project.Server.Library.dll assembly.

  5. Add the following lines to the global references in the source code for the event handler namespace:

    using Microsoft.Office.Project.Server.Events;
    using Microsoft.Office.Project.Server.Library;
    

    The Microsoft.Office.Project.Server.Library namespace includes the PSContextInfo class which contains the UserGuid and UserName properties for permission checks.

Procedure 2. To develop the event handler and compile the assembly:

  1. Create an event handler class that derives from the base abstract event receiver class you need for the business object. The following example uses the ProjectEventReceiver base abstract class.

    using System;
    using Microsoft.Office.Project.Server.Events;
    using Microsoft.Office.Project.Server.Library;
    
    namespace TestEventHandler
    {
        public class MyEventHandler : ProjectEventReceiver
        {
            . . .
        }
    }
    
  2. Create a method to override the base method for the specific event.

    Each event has a corresponding base method that you must override with your own implementation. For example, to write an event handler for the Publishing event of the Project business object, you override the OnPublishing method. In Visual Studio, IntelliSense lets you select the available base methods and completes the method framework as follows:

    public override void OnPublishing(PSContextInfo contextInfo, 
        ProjectPrePublishEventArgs e)
    {
        base.OnPublishing(contextInfo, e);
        . . .
    }
    

    You can delete the base.OnPublishing statement because the base method does no processing in an abstract class.

  3. Write the event handler implementation, using properties of the event argument object. For example, add the following lines to the OnPublishing method to write an entry to the Application event log. In this example, you also need to add the global using System.Diagnostics statement to get a reference to the system EventLog.

        // Create an EventLog instance and assign its source.
        EventLog myLog = new EventLog();
        myLog.Source = "Project Event Handler";
    
        // Get information from the event arguments, and 
        // write an entry to the Application event log. 
        string userName = contextInfo.UserName.ToString();
        string projectName = e.ProjectName.ToString();
        int eventId = 3651;
        string logEntry;
    
        e.Cancel = false;
    
        if (projectName.Substring(0, 3).Equals("Prj"))
        {
            logEntry = "User: " + userName + 
                "\nProject: " + projectName +
                "\nThe project name is valid. Publishing...";
            myLog.WriteEntry(logEntry, EventLogEntryType.Information, eventId);
        }
        else
        {
            logEntry = "User: " + userName + 
                "\nInvalid project name: " + projectName +
               "\nTo be published, the project name must start with 'Prj'.";
            myLog.WriteEntry(logEntry, EventLogEntryType.Warning, eventId);
            e.Cancel = true;
        }
    

    In the example, the log entry uses an optional application-specific eventID that enables you to filter for events. For a pre-event, set the Cancel property false to let the event continue, or true to cancel the event.

  4. Create a strong name key file for the assembly. For example, in a Command Prompt window change to your project directory and then type the following command:

    sn.exe -k testKey.snk
    
  5. Attach the key file to the project. With Visual Studio 2005, you set project properties rather than add key file information to the AssemblyInfo.cs file.

    1. In Visual Studio, click the project Properties command in the Project menu.

    2. Click the Signing side tab, select Sign the assembly, and browse to your testKey.snk file.

  6. Compile the code.

    1. In Visual Studio, press F6.

    2. Alternatively, you can use the command line. For example, type the following command in a Command Prompt window (all on one line):

      csc.exe /out:TestEventHandler.dll /target:library 
      /reference:System.dll 
      /reference:Microsoft.Office.Project.Server.Events.Receivers.dll 
      /reference:Microsoft.Office.Project.Server.Library.dll 
      /keyfile:testKey.snk MyEventHandler.cs
      

There are two ways to deploy the event handler assembly: Use XCopy to copy the assembly from another computer to a special event handler directory, or register the assembly in the global assembly cache of the Project Server computer.

Procedure 3a. To use XCopy deployment:

  1. (optional) On the Project Server computer, create a subdirectory named ProjectServerEventHandlers in the [Program Files]\Microsoft Office Servers\12.0\Bin directory.

  2. The system administrator must create a share that gives you full access to the [Program Files]\Microsoft Office Servers\12.0\bin directory or to the ProjectServerEventHandlers subdirectory on the Project Server computer. For example, create a share named OfficeServers for the directory [Program Files]\Microsoft Office Servers\12.0.

  3. In a Command Prompt window on the development computer change to the directory with the event handler assembly and then type the following command (use double-quotes around the destination directory if the path contains spaces):

    xcopy TestEventHandler.dll \\ServerName\OfficeServers\Bin\ProjectServerEventHandlers
    

    The event handler assembly is now copied to the Project Server computer in the directory [Program Files]\Microsoft Office Servers\12.0\Bin\ProjectServerEventHandlers.

Instead of using the XCopy procedure, if you have administrator logon access to the Project Server computer, you can register the event handler assembly in the global assembly cache.

Procedure 3b. To register the event handler assembly in the global assembly cache:

  1. There are several ways to add the assembly to the global assembly cache.

    1. In a Command Prompt window**, type the following command:**

      gacutil.exe /i TestEventHandler.dll
      
    2. Alternatively, click Start, click Run, and then type assembly to open the global assembly cache in a window. Then drag your assembly into the assembly window.

  2. Verify that your assembly is registered. Open the assembly window and scroll down to see your event handler assembly, as in Figure 1.

    Figure 1. The TestEventHandler is registered in the global assembly cache

    The TestEventHandler is registered in the GAC

  3. Copy the full name of the registered assembly to a text file for use when you register the event handler in Project Server. The full name contains the text name, culture, version, and public key token.

    1. Right-click the assembly in the global assembly cache, and then click Properties.

    2. In the TestEventHandler Properties dialog box, select the name (Figure 2), copy it, and then paste the name to an empty text file such as in Notepad.

    3. Copy the culture, version, and public key token, and paste each to the text file. The full name of the assembly follows:

      TestEventHandler, Version=1.0.0.0, Culture=Neutral, 
      PublicKeyToken=1e3db2b86a6e0210
      

      Figure 2. Copying properties of the registered assembly

      Copying properties of the registered assembly

    4. While your source code is available, copy the fully-qualified class name to the text file for use in registering the event handler with Project Web Access. For example, copy the namespace and class name to the text file as follows:

      TestEventHandler.MyEventHandler
      

Procedure 4. To register the event handler in Project Server:

  1. In Project Web Access, in the left pane, click Server Settings.

  2. On the Project Server Administrationpage, click Server-Side Event Handler Configuration (Figure 3).

    Figure 3. The Project Server Administration page

    The Project Server Administration page

  3. On the Events page, scroll in the Events list and click the Project link for the Publishing event (Figure 4).

    Figure 4. Selecting the Project Publishing event

    Selecting the Project Publishing event

  4. Click New Event Handler in the Event Handlers grid. On the Event Handler page (Figure 5), type the following values for the fields:

    1. Name Friendly name for the event handler.

    2. Description Optional description of the event handler.

    3. Assembly Name Full name of the assembly from the text file you prepared in the previous procedure, for example:

      TestEventHandler,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=1e3db2b86a6e0210
      
    4. Class Name Fully qualified name of the class in the assembly that implements the event handler, for example, TestEventHandler.MyEventHandler.

    5. Order If there are multiple event handlers associated with a single event, the order number determines the sequence in which the event handlers are invoked. The value can be from 1 to 999.

    Figure 5. Adding an event handler

    Adding an event handler

  5. Click Save.

    NoteNote

    Event registration is asynchronous and uses the Shared Service Provider and Windows SharePoint Services timer processes. If the timer periodicity is one minute, it can take up to two minutes to register the event handler with Project Server.

  6. Check that the event is added. In the Events list, click the Project link for the Publishing event again, and then scroll to the Event Handlers grid. If registration is completed, you should see the event handler in the list.

Procedure 5. To test the event handler:

  1. Create and publish a test project using Project Web Access, Project Professional, or another application such as LoginDemo.exe described in How to: Log on to Project Server Programmatically. The following test uses Project Web Access and is specific to the example code in this article.

    1. In the Home page, in the left pane under Projects, click Proposals and Activities.

    2. On the Proposals and Activities page, click New, and then click Proposal in the list.

    3. On the New Proposal page, complete the required project information fields, and then click Save.

    4. When the save is complete, click Publish on the project details page.

  2. Open the Event Viewer on the Project Server computer, click the Application events, and double-click the Information event with the source Project Event Handler. That is the source you assigned in the OnPublishing method. Figure 6 shows an example Event Properties dialog box.

    Figure 6. Viewing the event properties

    Viewing the event properties

    In the Event Viewer, you can click the View menu and then click Filter to specify an Event ID (3651 in the sample code).

Debugging an Event Handler

Registered event handlers run on the Project Server computer and are called by the Project Server Eventing service. To debug an event handler, you need to use Visual Studio 2005 and attach the debugger to the Project Server Eventing process.

Procedure 6: To debug a Project Server event handler:

  1. Register and test the event handler as described in the previous procedures.

  2. If you are debugging from a remote computer, you need to install and run the Microsoft Visual Studio Remote Debugging Monitor on the Project Server computer.

  3. In Visual Studio, open the event handler project that you registered, and on the Debug menu, click Attach to Process.

  4. In the Attach to Process dialog box (Figure 7), select the Default transport and browse to the Project Server computer name for the Qualifier. Click Select, and then in the Attach to options, select only the Managed box.

    Figure 7. Attaching the debugger to the Project Server Eventing service

    Attaching the debugger to the Project Server Event

  5. To put Visual Studio into debug mode, in the Available Processes list, click Microsoft.Office.Project.Server.Eventing.exe and then click Attach.

  6. On the Tools menu, click Options. Expand the Debugging node in the options list and click Symbols. Click the folder icon and paste the TestEventHandler project debug build directory path in the new symbol file location. Check Load symbols using the updated settings when this dialog is closed to load the TestEventHandler.pdb symbol file, and then click OK.

  7. In the code window MyEventHandler.cs, put a break point at the beginning of the OnPublishing method. If the breakpoint shows only a red outline with a yellow warning symbol, the TestEventHandler.pdb symbol file is not loaded.

  8. Trigger the Publishing event by publishing a project, and step through the OnPublishing event handler in Visual Studio.

  9. Debugging cannot work if you change the code and recompile after registering the event handler with Project Server. If you recompile, you must re-register the recompiled event handler, as follows:

    1. Unregister the event handler in Project Server.

    2. Remove the old event handler assembly from the global assembly cache.

    3. Register the recompiled event handler in the global assembly cache.

    4. Re-register the event handler in Project Server.

Example

The following sample is the complete code in the MyEventHandler.cs example file described in the previous procedures.

using System;
using System.Diagnostics;
using Microsoft.Office.Project.Server.Events;
using Microsoft.Office.Project.Server.Library;

namespace TestEventHandler
{
    public class MyEventHandler : ProjectEventReceiver
    {
        public override void OnPublishing(PSContextInfo contextInfo, ProjectPrePublishEventArgs e)
        {
            // Create an EventLog instance and assign its source.
            EventLog myLog = new EventLog();
            myLog.Source = "Project Event Handler";

            // Get information from the event arguments, and 
            // write an entry to the Application event log. 
            string userName = contextInfo.UserName.ToString();
            string projectName = e.ProjectName.ToString();
            int eventId = 3651;
            string logEntry;

            e.Cancel = false;

            if (projectName.Substring(0, 3).Equals("Prj"))
            {
                logEntry = "User: " + userName + 
                    "\nProject: " + projectName +
                    "\nThe project name is valid. Publishing...";
                myLog.WriteEntry(logEntry, EventLogEntryType.Information, eventId);
            }
            else
            {
                logEntry = "User: " + userName + 
                    "\nInvalid project name: " + projectName +
                   "\nTo be published, the project name must start with 'Prj'.";
                myLog.WriteEntry(logEntry, EventLogEntryType.Warning, eventId);
                e.Cancel = true;
            }
        }
    }
}

See Also

Tasks

How to: Customize E-Mail for Project Server Notifications

Concepts

Project Server Events

Using the ProjTool Test Application

Other Resources

Assembly Cache Viewer

Getting Started with a New Platform for Developers