A long time ago, I wrote an article on How to get the Global Address List programatically. The theory behind that article is still valid, but it only features a VBScript example. Since someone from the Microsoft Exchange Forum had trouble converting it to C#, I fired up Visual Studio and hacked something together. The result is somewhat more complete than the VBScript example, because it allows access to all address lists, not just the default global address list (GAL).

There are certain scenarios where it’s not feasible to require user interaction when accessing the private key of a smartcard. For example, a service does have the ability to provide a user interface. To use a key from a smartcard where a PIN is required, it must be provided to the smartcard using an alternative way. For some operations in .NET, one can use the CspParameters class to provide the PIN. But not all APIs which require smartcard access provide a way to use that class. The SSLStream is such a case. Here is a small extension method which sets the PIN for an X509Certificate2 instance:

The interesting piece here is, of course, the SetPinForPrivateKey method. It acquires a Win32 cryptographic context, sets the PIN and associates that pin with the certificate. Once you have an X509Certificate2 instance, you can set the PIN with just one line of code:

But writing Eventsinks has always been a pain because all this interop stuff, COM+ registration issues and more. Attached to this post you can find a small framework which simplifies writing event sinks (both synchronous and asynchronous ones).

The InfiniTec.Exchange.Eventing assembly contains several base classes from which you inherit your Eventsink. The only thing you have to do is to overwrite some methods (OnItemChanged, OnItemCreated, OnItemCreated) and you get relevant information about the event which happened in a compact object (EventInfo class). Below is a class diagram of the InfiniTec.Exchange.Eventing namespace:

Depending whether you want to create an asynchronous or synchronous Eventsink, you derive your sink from either SynchronousEventSink or AsynchronousEventSink. In you derived class, you simply override the notifications you want to catch. One thing all Eventsinks have in common is the registration process – Implemented by the OnRegisteringEvent. By returning false from this method you can prevent the registration on a certain url.

The synchronous Eventsink is called two times for each event: The first execution is called the Begin Phase; during this stage, the item is writable and you can even check for changes by loading the original item (via EventInfo.OpenItemLocally()). The seconds stage is called Commit Phase; the item is read-only now. If you need to share information about a particular event between these to stages, set the EventInfo.UserState property. The object graph is serialized using the BinarySerializer during the begin phase, so each instance used here must be serializable. This is a feature which was not possible with the interop files generated with tlbimp, because that tool did not generate the proper interop code. Since I’ve incorporated the complete interop code in this assembly, I fixed the signature of the affected interface.

Correctly deciphering the flags passed to the Evensink was an art of it’s own, so I’ve cleaned up those flags enumerations as well and routed them different methods (OnItemCreated with its CreationMode parameter and OnItemDeleted with its DeletionMode parameter).

At last, you don’t need the the regevent.vbs script any longer because I’ve included an EventSinkInstaller which registers your EventSink on a certain folder.

Now that you have created an Eventsink, you should add an installer so you can deploy the solution more easily:

1:using System.Collections;

2:using System.ComponentModel;

3:using System.Configuration.Install;

4:using InfiniTec.Exchange.Eventing;

5:

6:namespace TestSink

7: {

8: [RunInstaller(true)]

9:publicclass TestInstaller: Installer

10: {

11:publicoverridevoid Commit(IDictionary savedState)

12: {

13: Initialize();

14:base.Commit(savedState);

15: }

16:

17:publicoverridevoid Install(IDictionary stateSaver)

18: {

19: Initialize();

20:base.Install(stateSaver);

21: }

22:

23:publicoverridevoid Rollback(IDictionary savedState)

24: {

25: Initialize();

26:base.Rollback(savedState);

27: }

28:

29:publicoverridevoid Uninstall(IDictionary savedState)

30: {

31: Initialize();

32:

33:base.Uninstall(savedState);

34: }

35:

36:privatevoid Initialize()

37: {

38: var url = Context.Parameters["url"] + "/eventsink.evt";

39:

40: Context.LogMessage("Binding Url: " + url);

41:string criteria = Context.Parameters["Criteria"] ?? string.Empty;

42: criteria = criteria.Replace("$", "\"");

43:

44: Installers.Add(new EventSinkInstaller<TestSink>

45: {

46: Criteria = criteria,

47: EventMethods = EventMethods.SynchronousEvents,

48: Scope = MatchScope.Shallow,

49: Url = url

50: });

51: }

52: }

53: }

The reason why the Initialize() method is called in each of the methods is that the installer requires the url to the path on which the sink is registered. Unfortunately, the Context property is set after the constructor is run. What you basically need to do is to add an EventSinkInstaller the list of installers executed. The EventSinkInstaller has a type parameter which you can use to specify the type of sink registered. The installer will use this type parameter to determine the correct ProgId for the Eventsink. This example registers a synchronous event with a MatchScope of Shallow on the folder specified via the “url” parameter. Additionally, the constraint for the Eventsink is taken from the “constraint” parameter. This approach is superior to the regevent.vbs script because it lets you as the developer decide which parameters are fixed (the scope and type of the EventSink in this case) and which are variable, making the whole registration purpose less prone to errors.

Debugging

The InfiniTec.Exchange.Eventing assembly also defines a TraceSource which you can use for debugging. The TestSink application attached to this article contains the following application.config to activate the trace component:

1:<?xmlversion="1.0"encoding="utf-8" ?>

2:<configuration>

3:<system.diagnostics>

4:<traceautoflush="true"/>

5:<sources>

6:<sourcename="infinitec.exchange.eventing"

7:switchName="verbosity"

8:switchType="System.Diagnostics.SourceSwitch">

9:<listeners>

10:<addname="listener"

11:type="System.Diagnostics.TextWriterTraceListener"

12:initializeData="c:\temp\TextWriterOutput.log"/>

13:</listeners>

14:</source>

15:</sources>

16:<switches>

17:<addname="verbosity"value="All"/>

18:</switches>

19:</system.diagnostics>

20:</configuration>

Licensing

You may use this code (InfiniTec.Exchange.Eventing and InfiniTec.Common) in your application, regardless whether it is personal or business, free of charge.

A common question is how to retrieve the size of a given mailbox or the size of a folder structure via WebDAV. There is an example for this task on MSDN (Getting the Size of a Mailbox (WebDAV)). But that example is rather difficult to understand because the WebDAV requests are built using simple string concatenation, which is rather ugly. It is far better to create those requests using the XmlReader and XmlWriter classes (I’ve written about it in the article PROPPATCH requests using XmlReader and XmlWriter, Part 1).

The procedure to retrieve the cumulative folder size is this:

Issue a SEARCH request on the root folder of interest (for example the mailbox) and retrieve the size of all messages in that folder