Click here to Skip to main content
15,879,326 members
Articles / Programming Languages / C#
Article

Developing Managed Event Sinks/Hooks for Exchange Server Store using C#

Rate me:
Please Sign up or sign in to vote.
4.60/5 (31 votes)
17 Dec 20036 min read 424.9K   2.4K   68   129
This Article explains the Exchange Event Sinks and the creation of Event Sink Store Component using C#. Article also discusses about registering the event sink component to the component services and binding the event sink to an exchange user.

Introduction

When I had a project to develop a Managed Event Sink for Exchange Server Store, I hunted for some information over the web; surprisingly I could not get links that would really help me to get started immediately! Later, it took some time to get an outline on how to create managed event sinks, and at last, when I cracked it, I thought I shall share it :-) Hence, this article.

This article is targeted at intermediate users who have already developed event sinks in the COM World using VB/VC++ and others. If you are new to developing Event Sinks, I suggest that you read “Event Sinks” in the Exchange SDK documentation. The Exchange SDK has an excellent description on Event sinks. Anyways, I shall give a basic introduction to the Event Sinks.

So, what does an Event Sink Really mean?

Event Sink is a piece of code that gets triggered on predetermined events. A more classic jargon I can give as an example is “Hooks”, i.e. we hook and eye to an event [e.g.: a keyboard or event or a mouse event], and when the event occurs our custom code executes first and later the control is passed back to the original event if required.

Exchange Store Events

A similar concept is provided by Exchange Server, where in you can hook[!] or create event sinks for the events occurring at Exchange Server. Some of the events that can be hooked to are

1. Synchronous Events – Events that get triggered before an item [Mail, appointments, documents, tasks etc] is committed to the exchange server. These events pauses the exchange store thread until the event sink finishes executing. No other process can access the item during this event sink execution period as, event sink has the exclusive control over the items. Following are the events that are classified as Synchronous events.

a. OnSyncSave – fires when the item is saved to exchange, but before the changes are committed.

b. OnSyncDelete – fires when the item is deleted from exchange, but before the delete operation is committed.

2.Asynchronous Events – Events that get fired after an item is committed to the exchange server. These Async events do not block the exchange store thread. Following are the Asynchronous events.

a. OnSave – Fires after the item is saved to exchange and changes are committed

b. OnDelete – Fires after the item is deleted from the exchange and changes are committed.

3.System Events– Events that get fired based on some system wide actions on exchange server, the following are the system events.

a. OnMDBStartUp – This fires up when the Exchange Database is started.

b. OnMDBShutdown – This fires up when the Exchange Database is shut down.

c. OnTimer – Executes a piece of code at predefined intervals. This is a very useful event, which runs irrespective of specific events.

Synchronous and Asynchronous events are tied to a specific item or folder in the exchange store.

All these events are exposed in the Exchange CDOEX library [cdoex.dll] as interfaces. Fig 1.1 shows the object browser window of the CDOEX library.

Image 1

So What? What Can I Build?

Some of the applications that can be developed using Event Sink are,

  1. Notification Subsystems
  2. Global Timer applications
  3. Workflow based applications
  4. Automatic Categorization subsystems
  5. Store maintenance for administrators

Let's Code Now...

Fire up your VS.NET and choose new C# Class library project and name the project, hmm... let’s call it as “MyEventSink”.

On the Solution explorer, right click the project name and choose Properties, on the Project Properties page choose configuration properties choose build and set Register for COM Interop to True.

Image 2

Now, Copy the below files to the MyEventSink bin directory

  • exoledb.dll from exchange server bin directory (\program files\exchsrvr\bin)
  • cdoex.dll - \program files\common files\Microsoft Shared\CDO
  • msado15.dll - \Program Files\Common Files\System\ADO

Open up the VS.NET Command Prompt and navigate to MyEventSink bin folder, and create strong name keys for the above libraries. Key-in the following commands

> Sn –k exoledb.key
> Sn –k cdoex.key
> Sn –k msado.key

We need to create interop assemblies of the above library, in order to, create the interop assemblies we shall use the tlbimp tool. Key-in the following commands to create 3 interop assemblies.

tlbimp exoledb.dll /keyfile:exoledb.key /out:interop.exoledb.dll /namespace:CDO
tlbimp cdoex.dll /keyfile:cdoex.key /out:interop.cdoex.dll /namespace:CDO
tlbimp msado15.dll /keyfile:msado.key /out:interop.adodb.dll /namespace:ADODB

Copy these interop dll files to the debug folder. Switch back to VS.NET and add references to the above created interop DLL files. Modify the following attributes on the AssemblyInfo.cs

Under General Information section, modify

C#
[assembly: AssemblyTitle("MyEventSink")]
[assembly: AssemblyDescription("My Event Sink - Logu")] 

at version information section, create a new GUID and add

C#
[assembly: Guid("44E6847A-0012-42af-A317-1E1A9F0C853D")]

[Tip: You can create a new GUID by clicking Tools->Create GUID]

at sign information section, modify

C#
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("MyEventSink.key")]
[assembly: AssemblyKeyName("MyEventSink")] 

Now, Choose Project Properties and set the “Wrapper assembly key file” to MyEventSink.key and “Wrapper assembly Key Name” to “My Event Sink”

Image 3

Start the VS.NET Command Prompt and change directory to your project directory, and create a key, key-in the following,

> sn –k MyEventSink.key

Switch back to VS.NET IDE, and change the file name of class1.cs to a new name like “ExchEventSink.cs”, double click the .cs file to open.

Add,

C#
using CDO;
using ADODB;

modify the class definition code to resemble like below,

C#
[Guid("16369924-5F32-4E26-AE89-8308B5C162E2")]
C#
public class ExchEventSink: ServicedComponent , IExStoreAsyncEvents
{
public string ClassID = "F92EFC3A-FDD8-4225-B005-13FD3D5D54D1";
public string InterfaceId = "704A413F-F8FE-476B-9206-69AB6300D752";
public string EventsId = "DCC71BD5-6627-4FBF-BB5A-DB8FEA1EB177";

if you observe the above code, you can notice that we are implementing the IExStoreAsyncEvents interface, which implements the asynchronous events methods namely onsave and ondelete. We shall implement the same now, add the following to your code [check the attached zip file for more information]

C#
       public void OnSave(IExStoreEventInfo pEventInfo,
           string bstrURLItem, int lFlags)

         {
               try
               {
                     if(System.Convert.ToBoolean(lFlags))
                     {
                           CDO.Message iMessage=new
                               CDO.MessageClass();

                           string sFrom; string sDate;
         try
              {
                 iMessage.DataSource.Open(bstrURLItem,null,
                        ADODB.ConnectModeEnum.adModeRead,
                        ADODB.RecordCreateOptionsEnum.adFailIfNotExists,
                        ADODB.RecordOpenOptionsEnum.adOpenSource,"","");
                 FileStream fs = new FileStream(
                     @"c:\temp\MyEventSink.log",FileMode.OpenOrCreate);
                 fs.Write(Encoding.ASCII.GetBytes(bstrURLItem),0,
                     bstrURLItem.Length);
                 sFrom = iMessage.From;
                 sDate = iMessage.ReceivedTime.ToString();
                 fs.Write(Encoding.ASCII.GetBytes(sFrom),0,sFrom.Length);
                 fs.Write(Encoding.ASCII.GetBytes(sDate),0,sDate.Length);
                 fs.Close();
               }
   catch (Exception ex)
               {
                  throw (ex);
               }
         }
 }
               catch (Exception ex)
               {
                     throw (ex);
               }
}
public void OnDelete(IExStoreEventInfo pEventInfo, 
       string bstrURLItem, int lFlags)
 {
    try
      { }
    catch(Exception ex)
      {throw (ex);}
      }
  #endregion

In the above code, we are processing an exchange item on onsave method, and we create a LOG file. This is a simple code example; modify it to your requirements. [Check Exchange SDK on the lflags as this is very important, www.microsoft.com/exchange ]

Compile the class, you have your event sink component ready. Now, Open Component Services, under COM+ applications create new empty application and name it as “MyEventSink”, then, expand, components under MyEventSink and click “import components that are already registered”

And choose “MyEventSink.ExchEventSink” from the populated list.

Image 4

Now, the event sink component is registered to the server.

Image 5

We are done on our development part. Now, you can bind the component to any folder of exchange store, there are multiple ways to do this, I prefer the following,

RegEvent.vbs - I’ve attached the VBS file along with the download zip, this script creates the event registration for the specified folder. The following command binds the event sink to my inbox folder,

Image 6

I’ve included the vbs file along with the zip file, you can also get more information about this at [ www.microsoft.com/exchange ]

Exchange Explorer – this is a tool you get with Exchange SDK [check www.microsoft.com/exchange ]

Alternatively, you can build your own event registration [that’s a separate article by itself :-) ]

At last, we are done... We have created our own Managed Exchange Store Event Sink. You can also implement the Synchronous Events and the System Events as same as we have implemented the Asynchronous events.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: VS.Net 2005, .net 2 Pin
rjones060418-Dec-06 4:40
rjones060418-Dec-06 4:40 
AnswerRe: VS.Net 2005, .net 2 Pin
DaFlay28-Feb-08 11:31
DaFlay28-Feb-08 11:31 
Generalunsurmountable error Pin
omakase15-Jul-06 5:35
omakase15-Jul-06 5:35 
GeneralRe: unsurmountable error Pin
Kash_17-Jul-06 6:22
Kash_17-Jul-06 6:22 
GeneralRe: unsurmountable error Pin
omakase17-Jul-06 8:16
omakase17-Jul-06 8:16 
GeneralMissing just last piece of puzzle Pin
cord thomas10-Mar-06 12:05
cord thomas10-Mar-06 12:05 
QuestionDisclaimer Pin
Rom20003-Mar-06 1:12
Rom20003-Mar-06 1:12 
QuestionInstall on Exchange Server? Pin
Hamilton Fong22-Nov-05 12:14
Hamilton Fong22-Nov-05 12:14 
Does this need to be installed on exchange server itself?
I compiled everything on my development PC.
Registered the COM+ blah blah blah... on my dev PC.

Then I tried running the vbs command and it gave me:

Error Opening Connection : 3706 Provider cannot be found. It may not be properly
installed.

Is this because I'm an idiot trying to run this on my dev PC?

If so, how do I install on the exchange server?

Thanks all.

Ham.
AnswerRe: Install on Exchange Server? Pin
MagicJacky27-Dec-05 20:37
MagicJacky27-Dec-05 20:37 
GeneralRe: Install on Exchange Server? Pin
Parveen Beniwal5-Jul-06 19:22
Parveen Beniwal5-Jul-06 19:22 
GeneralRe: Install on Exchange Server? Pin
maria del monte2-May-07 2:50
maria del monte2-May-07 2:50 
AnswerRe: Install on Exchange Server? Pin
TC Smith9-Sep-08 7:50
TC Smith9-Sep-08 7:50 
GeneralI got error for opening connection Pin
BMWABCD14-Oct-05 11:30
BMWABCD14-Oct-05 11:30 
GeneralRe: I got error for opening connection Pin
NicDaniel25-May-09 0:10
NicDaniel25-May-09 0:10 
QuestionOnMDBStartUp Pin
melbinmathew5-Oct-05 17:26
melbinmathew5-Oct-05 17:26 
GeneralNot firing Pin
stryktiupos6-Sep-05 2:56
stryktiupos6-Sep-05 2:56 
GeneralRe: Not firing Pin
MagicJacky27-Dec-05 20:39
MagicJacky27-Dec-05 20:39 
General"COM + application Export wizard" error Pin
yogiberr25-Aug-05 3:11
yogiberr25-Aug-05 3:11 
QuestionHow to Get Ip Address On Smtp Event Sink in C# Pin
plb17-Mar-05 21:18
plb17-Mar-05 21:18 
AnswerRe: How to Get Ip Address On Smtp Event Sink in C# Pin
p_m_durrant16-Jun-05 2:45
p_m_durrant16-Jun-05 2:45 
QuestionListen for mail in specific inbox? Pin
daddion16-Feb-05 7:19
daddion16-Feb-05 7:19 
QuestionHow to listen to all the mailbox events Pin
xdong5-Feb-05 16:56
xdong5-Feb-05 16:56 
AnswerRe: How to listen to all the mailbox events Pin
Ryan McCauley23-May-05 7:10
Ryan McCauley23-May-05 7:10 
GeneralRe: How to listen to all the mailbox events Pin
p_m_durrant16-Jun-05 2:49
p_m_durrant16-Jun-05 2:49 
GeneralRe: How to listen to all the mailbox events Pin
chrish196821-Jun-05 2:56
chrish196821-Jun-05 2:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.