OUTBOX: Introduction to Exchange Store Event Sinks Part 2



Coming from Exchange 5.5 Event Service Scripts to Exchange Store Event Sinks involves more than just understanding the new events available and the registration process.  Exchange 5.5 event scripts are written in VBScript with CDO 1.21 as the API to interact with Exchange data.  Store Event Sinks can be written in VBScript, VB6, managed (.NET) code, and C++ they use ExOLEDB with ADO and CDOEX to interact with Exchange data.  This is greatly improves scalability and performance but requires a bit of retooling for the developer to be comfortable in their new surrounds.  The following information discusses what you need to know about the web store how to interact with data using CDOEX and ExOLEDB.

 

Exchange Store

 

One important distinction to make between Exchange 5.5 and Exchange 200x is the storage architecture.  This is an important consideration when looking at the new API’s available in Exchange 2000 and 2003 because many of the new API’s relate to what is called Web Store or stream database that is added to the Exchange storage system.  Exchange store event sinks, WebDAV, CDOEX, and ExOLEDB with ADO all work against the web store primarily as opposed to CDO 1.21 and MAPI which work against the ESE database (which was part of Exchange 5.5 as well and is commonly referred to as the MAPI database).  We will talk about ExOLEDB and CDOEX mainly because that is what you will use in an Exchange Store Event Sink.

 

Exchange Storage Architecture


 


 

CDOEX, ADO, Properties, and Exchange SQL

 

The web store uses native intermittent content such as MIME which allows access through ExOLEDB with ADO and WebDAV and the use of SQL-like queries to find information.  This is quite helpful and a little more intuitive for the database programmer.  Each item (folders and messages) in the store can be created, modified, and searched like a row in a database were item properties are columns. 

 

Folders can be used like tables and rows, for example to query the subfolders of a given root folder you would select the URL from all items in the root folder where the item “isFolder” column is “true”…


Select “DAV:href” from scope(‘shallow traversal of <ROOT FOLDER URL>) Where “DAV:isfolder” = True

The following link provides a description of the SQL predicates supported against the web store.

 

Exchange Store SQL


 

Add just like in a database when you write a query like the one of above you need to know two key pieces of data specific to your store, the table name and the available columns.  The table name is pretty easy to identify as it is the folder you what to query from.  The column names differ for each item type with some overlap.  For example appointment items and contact items have most of the same properties of a basic message but they also have their own unique properties that relate to their functions.

 

The following link provides a listing of properties available on different items organized by namespace.  You will use the full namespace and property name when pulling fields from the Fields collection of a CDOEX object or querying in WebDAV or ADO.

 
Properties by Namespace

 

The interesting thing about this paradigm is that it is often quite easy for a database developer to walk in and start using ExOLEDB with ADO and WebDAV to execute these kind of queries against Exchange.  However, a developer coming from MAPI or CDO 1.21 is usually left looking for the objFolder.Folders collection.  ExOLEDB with ADO and WebDAV provide a way to retrieve raw information from the server, they are not an object model.  CDOEX provides some interfaces and CoClasses to provide a bit of an object model for interacting with the web store.

 

MSDN Reference for CDOEX CoClasses, Interfaces, etc.


 

In event sink development you will typically stay within the interfaces of the CDOEX object you open with the URL passed into the event interface.  Especially when working with meetings and contacts note that CDOEX provides a supported way for working with these item types.  ExOLEDB with ADO and much of WebDAV offers you raw access to the items in the web store, complex item types like appointments and contacts require CDOEX or special WebDAV commands to ensure that all the appropriate properties are being set to ensure that end user clients display and use the information appropriately.

 

It is important to understand the limitations of each API and where you should use which.  CDOEX and ExOLEDB with ADO should only be used on an Exchange server, specifically they can only be used the Exchange server which hosts the mailboxes or public folders you want to access.  WebDAV should be used to remotely access Exchange mailboxes and folders that may not reside on the server it is running on, it can also be executed on a non-Exchange server.  All of these technologies are supported with managed (.NET) code, CDO 1.21 and MAPI are NOT supported with managed code.

 

813349 Support policy for Microsoft Exchange APIs with the .NET Framework applications
http://support.microsoft.com/default.aspx?scid=kb;EN-US;813349

 

Examples

 

Exchange Tasks


This is a great starting place when you are looking to see what you can do with Exchange API’s.  There are all kinds of great code samples here to allow you to do all kinds of stuff against the store.  I have pulled a couple samples out that relate to some common tasks developers do inside event sinks.

 

Adding an Appointment to the Calendar


 

Responding to a Meeting Request


 

Listing Inbox Contents Using ADO

Comments (5)

  1. Alex says:

    I am having a problem with using ExOLEDB with ADO. When I run the following query:

    SELECT  
    “urn:schemas:httpmail:subject” as “SUBJECT”,
    “urn:schemas:httpmail:textdescription” as “SUMMARY”,
    http://schemas.microsoft.com/mapi/priority“ as “PRIORITY”,
    http://schemas.microsoft.com/exchange/tasks/is_complete“ as “COMPLETED”,
    http://schemas.microsoft.com/exchange/tasks/dtstart“ as “STARTDATE”,
    http://schemas.microsoft.com/exchange/tasks/dtdue“ as “DUEDATE”,
    http://schemas.microsoft.com/mapi/proptag/x0FFF0102“ as “ENTRYID”,
    “urn:schemas:mailheader:message-id” as “MESSAGEID”,
    “DAV:href” as “URL”,
    http://schemas.microsoft.com/mapi/proptag/x002b000b“ as “PRIVATE”

    FROM “http://myserver/exchange/alexa/Tasks“ WHERE “DAV:ishidden” = false AND “DAV:isfolder” = false
    AND “DAV:href” = ‘http://myserver/exchange/alexa/Tasks/Newtask.EML

    I get zero records, even though that url is valid. If replace the “DAV:href” in the predicate to “DAV:displayname”:
    AND “DAV:displayname” LIKE ‘%Newtask.EML’

    I get the record.
    The only problem is, that sometimes there might be a name duplication withing the folder (I truncate the display name if it has special characters in it)
    I get around that by comparing the href value to the url value I get from the server, and that comparison works as expected, but for the query results, and not during the query.

    Basically, I think it’d be much better if I can search by url (href) but I alway get 0 records.

    Any suggestions?

    TIA.

    Alex

  2. mstehle says:

    Please note the following MSDN documentation…

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_exch2k_sql_non-searchable_properties.asp

    DAV:href is a non-searchable property.  If you are looking to pull properties from one particular item you should use a PROPFIND request…

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_webdav_propfind.asp

  3. Marvin42 says:

    Exchange Tasks:

    I have looked everywhere for help with Exchange and Tasks. Thanks to Alex in a previous comment I managed to get some code to Get Tasks from Exchange using WebDAV. Now I need to adapt that code to Add a Task to WebDAV and I haven’t magaed to get it to work yet. Any Help would be useful.

    Get Tasks using WebDAV:

    ————————

    strQuery.Append("<?xml version="1.0"?>");

                   strQuery.Append("<g:searchrequest xmlns:g="DAV:">");

                   strQuery.Append("<g:sql>SELECT "urn:schemas:httpmail:textdescription", ");

                   strQuery.Append(""urn:schemas:httpmail:subject", ");

                   strQuery.Append(""http://schemas.microsoft.com/exchange/tasks/dtdue" AS DueDate, ");

                   strQuery.Append(""http://schemas.microsoft.com/exchange/tasks/dtstart" AS StartDate, ");

                   strQuery.Append(""http://schemas.microsoft.com/exchange/tasks/percentcomplete" AS Percent, ");

                   strQuery.Append(""http://schemas.microsoft.com/exchange/tasks/is_complete" AS Compelte, ");

                   strQuery.Append(""http://schemas.microsoft.com/mapi/priority" AS Priority ");

                   strQuery.Append("FROM Scope(‘SHALLOW TRAVERSAL OF "" + http://ipaddress/exchange/username/tasks/ + ""’) ");

                   strQuery.Append("WHERE "DAV:isfolder" = False and "DAV:ishidden" = False");

                   strQuery.Append("</g:sql></g:searchrequest>");

    —————————————

    Here is what I tried for Adding tasks, using the same basic XML i use for adding Calendar appointments.But can;t get it to work for tasks:

    ————————————–

    <?xml version="1.0" ?>

    – <g:propertyupdate xmlns:g="DAV:" xmlns:e="http://schemas.microsoft.com/exchange/&quot; xmlns:mapi="http://schemas.microsoft.com/mapi/&quot; xmlns:mapit="http://schemas.microsoft.com/mapi/proptag/&quot; xmlns:x="xml:" xmlns:task="http://schemas.microsoft.com/exchange/tasks/&quot; xmlns:dt="urn:uuid:015db9e2-d950-45a0-b040-6b9352d80aa7" xmlns:header="urn:schemas:mailheader:" xmlns:mail="urn:schemas:httpmail:">

    – <g:set>

    – <g:prop>

     <g:contentclass>urn:content-classes:task</g:contentclass>

     <e:outlookmessageclass>IPM.Task</e:outlookmessageclass>

     <mail:subject>Zztop</mail:subject>

     <mail:textdescription>Go zz go</mail:textdescription>

     <task:dtdue>09/08/2006 00:00:00</task:dtdue>

     <task:dtstart>09/08/2006 00:00:00</task:dtstart>

     </g:prop>

     </g:set>

     </g:propertyupdate>

    ———————————–

    Any ideas anyone?

  4. mstehle says:

    Creating Tasks with WebDAV is not supported because we don’t have business logic implemented to make it work right.  However here is a sample that might work for you…

    http://groups.google.com/group/microsoft.public.exchange.development/browse_thread/thread/6641ba7a465f624c/0e8d8aa8cce9f32f