Welcome to MSDN Blogs Sign in | Join | Help

Announcing EWSEditor 1.5!

Over the past year I’ve been working with the new Exchange Web Services Managed API and I have to say, it’s a wonderful thing – especially compared to working with the Visual Studio generated proxy classes for Exchange Web Services.  While working with Exchange Web Services (EWS) early in the Exchange 2007 release it became apparent to me that an editor tool in the spirit of MFCMAPI built on top of EWS might be useful.  At the time I started working on such an editor and based it off the Visual Studio generated proxy classes.  To my delight I was soon introduced to an API that the product team was working on to make my life (and that of any other EWS developer using .NET languages) much easier – the EWS Managed API.

I immediately started work on converting my editor code from proxy classes to this new API.  This process was about 75% deleting code and 25% writing new EWS Managed API code.  I was replacing hundreds of lines of proxy class code with half as much (or less) EWS Managed API code.  Over the coming months I explored the features of the API and was able to quickly add new functionality to the editor because I could focus on UI code rather than wordy proxy class code.

Out of all of this work comes EWSEditor!  This initial public release is called version 1.5 because it has been used internally for a while by my team.  There are still features I’m working on and basic API coverage that will come together over time.  It’s a work in progress but still very useful in its current state so I wanted to get it out to the public.  Please feel free to send me suggestions, comments, bugs, etc.  There is an Issue Tracker and Discussions page on the project site – feel free to use them.

From the project site, here are the goals of EWSEditor

“1. Demonstrate the Exchange Web Services Managed API functionality and simplicity to developers through its source code.
2. Demonstrate the Exchange Web Services SOAP traffic used to perform actions initiated through an explorer user interface.
3. Assist non-developers in debugging and understanding Exchange stores by exploring items, folders, and their properties in depth. “

The plan right now is to do an update every two months (next one will be in January).  Since this is the first public release there might be an interim release if some blocking issue come up.  Available for download are release notes which I’ll add to with each release to track the changes over time and give an overview of what is new.  Here are the notes from the 1.5 release…

“1.5 Release – 11/6/2009

The first public release of EWS Editor! The basic feature set is still be flushed out but it is still a very useful tool. There are three feature areas of EWS Editor: General UI, Support Tools, and API Coverage. The focus of this release was to establish the UI design and flow of the application, solidify some useful support tools, and illustrate the direction of the application.

There are some gaps in CRUD tasks across item and folder properties and items themselves. The major focus of upcoming releases will be to fill in these gaps before moving on to new features.”

If your interested, download the source or just the binary and try it out.  Here are some the highlighted features from the release notes…

Exchange Service Profiles

Exchange Service Profiles describe not only the connection information for calls specified in the ExchangeService class but also the root folder to use in the tree view of EWS Editor. Multiple ExchangeService objects can be displayed at one time using unique configurations. This allows folders on multiple servers and server versions to be displayed at one time or displaying the same folders using different credentials.

Exchange Service Profiles can be saved to an XML file which contains the configuration information (sans specified passwords) so that it can be reloaded easily. If a profile requires credentials then a prompt will appear when loading the Services Profile to enter the credentials.

image image

View properties of ExchangeServices, Folders, and Items

The PropertyDetailsGrid display first class properties for all nodes of the tree view starting with the root, ExchangeService node and all the way to the folder contents form, displaying first class properties for Items in a folder. Under the View menu the PropertySet used to retrieve item or folder data can be configured to customize which schema properties and extended properties are displayed in the PropertyDetailsGrid.

clip_image006clip_image008


Extended Property Lookup

A number of known extended MAPI properties have been indexed in EWS Editor. Extended properties can be added to the PropertyDetailsGrid through a look up using a known constant name for the property such as PR_SUBJECT, PidTagSubject, etc. An Extended Property Lookup tool provides a way to quickly get the property information for a known constant.

clip_image010

Request and response logging

While EWS Editor is running, all requests and responses are logged to a file. The Chatter Log tool is used to view the history of requests and responses.

clip_image012

Posted by mstehle | 0 Comments

FYI: New Version of Exchange Remote Connectivity Analyzer Released (ExRCA) with new Exchange Web Service Tests!

From the Exchange Team blog:

“Today we released an updated version of the Exchange Remote Connectivity Analyzer. For those of you not familiar with this site, it is a Web-based tool that helps you troubleshoot connectivity issues. The tool simulates several client logon and mail flow scenarios. When a test fails, many of the errors have troubleshooting tips to assist you in correcting the problem. For more information, see our previous blog post here.

Additional tests

  • Exchange Web Services - This allows you to perform connectivity testing for Exchange Web Services client such as Entourage. Developers can also use the Service Account Verification test to ensure things are configured and working properly for access with an alternate account or Exchange Impersonation.”

Brad Hughes came up with this awesome tool and I’ve been working with him to add these EWS tests to ExRCA.  There are two basic tests that you can do at this time with Exchange Web Services: 1) Test the ability of an account to perform basic Exchange Web Services tasks like Synchronization, Notification, Availability, and OOF or 2) Test the ability of a service account to access a mailbox through delegate access or Exchange Impersonation.  The first set of tests may be more useful to Exchange Administrators testing for Entourage client connectivity and as well as Availability and OOF which are used by Outlook too.  The Service Account Access test is a quick way to test and diagnose issues with service accounts accessing other mailboxes.

image

 

Both of these tests should be run against a test mailbox with an empty Inbox and Calendar folder because they will attempt to create and delete test items.  During the execution of the test ExRCA looks to ensure the Calendar and Inbox of the specified mailbox are empty before running.

EWS: Exchange 2007 RTM vs. SP1 Specifying MeetingTimeZone's TimeZoneName when creating an Appointment

Prior to Exchange 2007 SP1 an article was published with some specific guidance related to handling time zones in calendar item tasks.  Contrary to Best Practices for Using Exchange Web Services for Calendaring Tasks, specifying just a MeetingTimeZone TimeZoneName when creating a CalendarItem appears to work in Exchange 2007 SP1 and later.  The best practices says not to submit the TimeZoneName in MeetingTimeZone because it will be ignored, though there is a hint that this might not apply to Exchange 2007 SP1:

“Do not supply the optional TimeZoneName element when you create calendar items. In the initial release version of Exchange 2007, the TimeZoneName element is ignored on incoming requests.”

However, take the following request which properly creates a CalendarItem in the Eastern time zone:

        <t:CalendarItem>

          <t:ItemClass>IPM.Appointment</t:ItemClass>

          <t:Subject>Appointment in Eastern Time</t:Subject>

          <t:Start>2009-06-26T09:00:00.000</t:Start>

          <t:End>2009-06-26T09:30:00.000</t:End>

          <t:MeetingTimeZone TimeZoneName="Eastern Standard Time">

          </t:MeetingTimeZone>

        </t:CalendarItem>

 

From the best practices, the following statement intends to confirm that TimeZoneName is not ignored in Exchange 2007 SP1 and can be used by itself to define a time zone:

“In Exchange Server 2007 Service Pack 1 (SP1), BaseOffset is an optional element, and supports MeetingTimeZones that specify the TimeZoneName only.”

This is quite true in fact, were in Exchange 2007 pre-SP1 specifying the offset elements was a requirement and TimeZoneName was ignored; in Exchange 2007 post-SP1 the TimeZoneName is actually the preferred method for declaring a time zone.  Furthermore, offset and transition values should only be set when specifying a custom time zone.  Otherwise, standard time zones should be specified using TimeZoneName which is the name of the time zone as it appears in the registry key name on the Exchange CAS server.  Then the Exchange server will pull the transition and offset information from the registry for the time zone you specified.  Here is an image showing where the registry keys are:

image

Bottom line, with Exchange 2007 SP1 don’t specify time zone offset and transition values for known time zones – use the TimeZoneName instead.  This will help your application work seamlessly with any updates to known time zone definitions in the future.

EWS: UID not always the same for orphaned instances of the same meeting.

Earlier I linked to a post by Henning Krauses which discusses searching for a meeting using the UID and GlobalObjectId properties.  The point of UID is to provide a unique identifier for a meeting across the calendars each attendee to the same meeting.  Henning gave some expert advise for using GlobalObjectId instead of UID in a FindItem request to locate instances of a recurring meeting in different user’s calendars.  As noted in his article, in Exchange 2007 pre-SP2 the UID property is built from GlobalObjectId – he even shows how to convert from UID to GlobalObjectId.

Using GlobalObjectId poses a problem however…If you were to create a recurring appointment and invite one attendee for only one instance of that recurring appointment that attendee ends up with only the one exception instance of the parent recurring appointment in their calendar.  This is called an “orphaned” appointment.  This type of appointment’s GlobalObjectId has additional information in it related to the exception date (for more information look at PidLidGlobalObjectId in MS-OXOCAL).  The bottom line here is that this orphaned instance in this one attendee’s calendar will have a GlobalObjectId, and therefore UID, which doesn’t match the related appointments in the other attendee’s and organizer’s calendar.  Henning’s code won’t work in this specific scenario…

So what now?  Is this a bug in Exchange?  Is there another property Henning could use?  The answer to both questions is, yes!

There is another property, CleanGlobalObjectId, which was defined just for this scenario.  If you look at the documentation for this property, the remarks confirm that this property specifically addresses the issue described above:

“The format of this property is the same as that of LID_GLOBAL_OBJID ( PidLidGlobalObjectId). The value of this property must be equal to the value of LID_GLOBAL_OBJID, except the YH, YL, M, and D fields must be zero. All objects that refer to an Instance of a recurring series (including an orphan instance), as well as the recurring series itself, will have the same value for this property.”

So all Henning needs to do in his sample is change it to use the CleanGlobalObjectId instead of GlobalObjectId.  Now, it would be logical to assume that Exchange should base the UID property off of the CleanGlobalObjectId too instead of GlobalObjectId.  In fact, we’ve done just that.  In Exchange 2007 SP2 UID is based on the CleanGlobalObjectId instead of GlobalObjectId.  Because SP2 just came out and many customers may wait to install it because of the schema changes you’ll want to keep the workaround above in mind when working with GlobalObjectId and UID in Exchange Web Services.

OUTBOX: Setting ‘Don’t Crawl On Me’ via Outlook’s object model

A while ago Steve posted information about how to turn of various types of “crawling” in Outlook via named properties that can be set on a store to tell Outlook whether or not it is okay to “crawl” the store in different scenarios.  There are cases where you might have tons of folders in a store and you don’t want Outlook to enumerate all these folders because it would impact performance.  I was recently asked if these properties could be set via a simple VB script.  Turns out it is pretty straight forward to set this property via the PropertyAccessor in Outlook’s object model.

The following script will work with Outlook 2007 and greater.  It is simply a sample script which can be used to set the CrawlSourceSupportMask to enable or disable Outlook crawling a store to look for Contact, Task, and Calendar folders in an opened store.  You could easily modify this script to set ArchiveSourceSupportMask if you needed to – this disables/enables Outlook crawling open stores looking for folders that need to be archived.

Option Explicit
Main()
Sub Main
    On Error Resume Next
    Dim oApplication 'As Outlook.Application
    Set oApplication = CreateObject("Outlook.Application")
    If Err.number <> 0 Then
        DisplayError "Unable to get Outlook application object, " & _
                     "make sure Outlook 2007 is installed on this computer."
        Exit Sub
    End If
    Dim oSession 'As Outlook.Namespace
    Set oSession = oApplication.Session
    If Err.number <> 0 Then
        DisplayError "Unable to get current Outlook session, make sure " & _
                     "Outlook 2007 is running."
        Exit Sub
    End If
    
    MsgBox "Choose an Outlook message store to configure.", _
                1, _
                "Configure Outlook Do Not Crawl"
    
    Dim oFolder 'As Outlook.Folder
    Set oFolder = oSession.PickFolder
    If oFolder Is Nothing Then
        Exit Sub
    End If
    If Err.number <> 0 Then
        DisplayError "Unable to get Folder."
        Exit Sub
    End If
    Dim oStore 'As Outlook.Store
    Set oStore = oFolder.Store
    
    If Err.number <> 0 Then
        DisplayError "Unable to get Store."
        Exit Sub
    End If
    
    Dim choice
    choice = MsgBox ("Do you want Outlook to crawl the message store you selected?", _
                4, _
                "Configure Outlook Do Not Crawl")
    Dim CrawlSourceSupportMask
    CrawlSourceSupportMask = "http://schemas.microsoft.com/mapi/string/" & _
       "{00062008-0000-0000-C000-000000000046}/CrawlSourceSupportMask"
    Dim propValue
    propValue = oStore.PropertyAccessor.GetProperty(CrawlSourceSupportMask)
    If Err.number = -2147221233 Then
        MsgBox "CrawlSourceSupportMask is not currently set, click OK to create it and set it."
        Err.Clear
    ElseIf Err.number <> 0 Then
        DisplayError "Unable to get CrawlSourceSupportMask property."
        Exit Sub
    End If
    
    If choice = 6 Then
        oStore.PropertyAccessor.SetProperty CrawlSourceSupportMask, CLNG(1)
    ElseIf choice = 7 Then
        oStore.PropertyAccessor.SetProperty CrawlSourceSupportMask, CLNG(0)    
    End If
    
    If Err.number <> 0 Then
        DisplayError "Failed to set CrawlSourceSupportMask."
        Exit Sub
    End If
    If choice = 6 Then
        MsgBox "Success!  Do Not Crawl has been enabled on this store."
    ElseIf choice = 7 Then
        MsgBox "Success!  Do Not Crawl has been disabled on this store."
    End If
    
End Sub
Sub DisplayError(strMessage)
    MsgBox strMessage & vbCrlf & vbCrlf & _
           "Error Information" & vbCrlf & _
           "Number: " & Err.number & vbCrlf & _
           "Description: " & Err.Description, ,"Error!"
End Sub

FYI: DeleteItem behavior, Exchange 2010 SDKs, EWS performance and SyncFolderItems, and Named Property Mapping in Exchnage 2007+

Fellow developer support engineer, Patrick Creehan, has any interesting post about the delta between the documentation of DeleteItem calls and the actual behavior involving including the ChangeKey in the ItemId of the item you want to delete.  In theory the ChangeKey would be required for DeleteItem requests to ensure that you know you have evaluated the latest version of the item and decided to delete it.  If you pass an ItemId with a stale ChangeKey, you should get a error indicating this isn’t the latest version of the item and you can retrieve it to make sure you still want to delete it.  This is how an UpdateItem request works.  As Patrick’s post indicates, DeleteItem doesn’t work the same way UpdateItem works – it just ignores the ChangeKey and does the delete no matter what.  Patrick has a workaround to provide similar functionality in case you need it.

The Exchange API team announced, they’ve posted a beta SDK for Exchange 2010 on MSDN.  In their post they highlight the most notable change in the structure of this SDK:

“…For earlier product releases, all Exchange developer documentation is included in a single SDK. For Exchange 2010, documentation for each technology area is published in a separate SDK, making it quicker and easier for you to find information that you need. The following SDKs are available online for Exchange 2010 Beta:

Henning Krause posted a couple interesting articles that go along with my earlier, performance themed EWS posts (part 1 & part 2).  His first post is about processing items in a folder using the EWS Managed API, he walks through some of missteps I see customer make when they complain about how “slow” EWS is – as he points out it often comes down to choosing the right tool for the job and synchronization is often over looked by novice EWS developers who choose to loop through an entire folder looking for changes instead.  His second post is more about limiting the requested PropertySet to increase the performance of your EWS code – something I have pointed out earlier with GetItem and FindItem calls but it is good to reinforce this concept in SyncFolderItem calls as well. 

Speaking of GetItem vs. FindItem calls – Henning has a third post which shows you how to get the message body with a FindItem request even though technically you can’t request the “item:body” schema property in a FindItem’s PropertySet.  His post points out an important concept which is that schema properties (or “first class properties” as they are sometimes called) are tied back to extended properties which are the “raw values”.  Often times certain limitations are applied to the schema properties because they calculations can be expensive or unavailable at a certain time – however in some cases you can get around this by using and understanding the correlating extended properties.

Jason Nelson posted a couple items (round 1 and round 2) on the Exchange team blog about named property mapping detailng the history and problems with this mapping and upcoming changes in Exchange 2007 SP2 and Exchange 2010.  Most notable from the “round 2” post is that in Exchange 2007 SP2 and Exchange 2010 “…no x-headers are ever promoted to individual properties if a client has not already requested (and mapped) them. Not even authenticated submissions can create new named property mappings.”  This could pose a problem if your application relies on these headers to do processing, if you are using an Exchange API with property access like EWS, MAPI, CDO 1.21, WebDAV, or Outlook 2007+ object model then fear not, “…x-headers are still stored in PR_TRANSPORT_HEADERS and still accessible to MAPI clients but they are not individual properties.”

However, if your application uses IMAP the story is different…

“Exchange2007 does not contain an STM file - it doesn't save the original mime content. Messages are converted to MAPI. IMAP has the ability to search based on header values, but if these are not promoted, the result is that the message is not contained in the results. If a client has previously mapped t he header in question (a MAPI client) then messages delivered after this will have the x-header promoted as an individual property.”

FYI: Can’t use Exchange Impersonation with GetUserOofSettings, SetUserOofSettings, or GetUserAvailability

I kept forgetting about this so maybe blogging it will help me remember.  As this thread confirms – you can’t call GetUserOofSettings, SetUserOofSettings, or GetUserAvailability when using Exchange Impersonation.  If you try to do this you’ll get an error that the Service Account is not the mailbox owner.

Exchange API Team Blog: Exchange Impersonation vs. Delegate Access…

The Exchange API team has a new post to explaining the differences between using Exchange Impersonation vs. Delegate Access to access an Exchange mailbox using Exchange Web Services.  I’ve seen first hand that there is a gap in understanding the difference between the two and when to use one versus the other.  This post goes a long way to address some of the confusion.

An important note that some people miss is the differentiation between Windows and Exchange impersonation – they’re not the same thing and more importantly, they aren’t even related…

“Exchange Impersonation is different than Windows Impersonation. Windows Impersonation is an operating system concept that requires you to set Kerberos constrained delegation. Exchange Impersonation is a simpler authorization mechanism that is designed for use only within Exchange Web Services (EWS). For more information about Windows Impersonation, see Client Impersonation on MSDN.”

Conversely, the posts describes delegate access as…

“Delegate access is used in scenarios in which there needs to be a one-to-one relationship between users. One common application of delegate access is the sharing of calendars between users, such as when an admin manages an executive’s calendar, or a when handful of individuals working on a project need to coordinate calendars…

…Individual users can grant and remove delegate access to their own mailboxes through several mailbox clients, such as Microsoft Outlook, Outlook Web Access, or Exchange Web Services-based clients. A mailbox owner does not need administrator rights to grant another user delegate access to their mailbox.”

…To be clear, delegate access can be granted by an administrator on an entire mailbox (but not to specific folders within the mailbox) using the Add-MailboxPermission cmdlet but as the above statement points out individuals can also grant delegate access for other users to access specific folders in their mailbox or the entire mailbox.

A major difference between impersonation and delegation is that as far as Exchange Web Services and Outlook Web Access are concerned there is no way to assign a single delegate access to multiple mailboxes expect by establishing the delegate relationship for each individual mailbox.  I’ve talked about this before, the Exchange team describes it this way…

“For delegate access, there is no option to set up a single delegate for multiple mailboxes. A relationship must be established for each user who needs to access a given mailbox…

…You must explicitly grant delegate access for any new users who are added.”

…This is a great post and a worthwhile read but from working with many customers to help them understand these concepts, I’d like to add some additional information and emphasize some key points…

Understanding the Requests

To emphasize a side point in the blog post there are three methods of mailbox to access a mailbox: Exchange Impersonation, Delegate Access, and Direct Logon.  The article doesn’t provide examples of what the XML looks like in each type of access request using Exchange Web Services.  For understanding, I’ve provided them below…

Direct Logon

<GetFolder>
  <FolderShape>
    <t:BaseShape>AllProperties</t:BaseShape>
  </FolderShape>
  <FolderIds>
    <t:DistinguishedFolderId Id="inbox"/>
  </FolderIds>
</GetFolder>

Delegate Access

<GetFolder>
  <FolderShape>
    <t:BaseShape>AllProperties</t:BaseShape>
  </FolderShape>
  <FolderIds>
    <t:DistinguishedFolderId Id="inbox">
      <t:Mailbox>
        <t:EmailAddress>
         
someoneelse@contoso.com
        </t:EmailAddress>
      </t:Mailbox>
    </t:DistinguishedFolderId>
  </FolderIds>
</GetFolder>

Exchange Impersonation

<soap:Header>
  <t:ExchangeImpersonation>
    <t:ConnectingSID>
      <t:PrimarySmtpAddress>
        someone@contoso.com
      </t:PrimarySmtpAddress>
    </t:ConnectingSID>
  </t:ExchangeImpersonation>

</soap:Header>
<soap:Body>
  <GetFolder>
    <FolderShape>
      <t:BaseShape>AllProperties</t:BaseShape>
    </FolderShape>
    <FolderIds>
      <t:DistinguishedFolderId Id="inbox"/>
    </FolderIds>
  </GetFolder>
</soap:Body>

…The example above is for explicit delegate access.  You can also access a mailbox using implicit delegate access by specifying a FolderId which links to another mailbox.  All Ids returned by EWS embed their mailbox information in them so requesting them without explicitly specifying a mailbox will also work.

Putting It All Together

The terms used here come from the way Exchange Impersonation (also called Server-to-Server or S2S Authentication) is explained in the Inside Exchange Web Services book.  The book describes three types of accounts that come into play when accessing a mailbox: the Service account, the Act As account, and the Mailbox account.  Understanding how these accounts are affected by different mailbox access types is important.  The Service account is the account used to generate the XML requests and authenticate to the virtual directory, the Act As account is the account which will be used to authorize actions taken against a mailbox, and the Mailbox account is the actual resource you are trying to access.  In the grid below suppose you have an EWS application which runs as a user called ApplicationAccount, here is how the different access types affect each account context…

Access Type Service Account Act As Account Mailbox Account
Exchange Impersonation ApplicationAccount the impersonated account as specified in the ExchangeImpersonation property of the request any mailbox that the Act As account has mailbox rights to through Add-MailboxPermission or through permissions granted through Outlook, OWA, or EWS directly on a mailbox folder.
Delegate Access ApplicationAccount always ApplicationAccount any account or mailbox folder that ApplicationAccount has mailbox rights to through Add-MailboxPermission or through permissions granted through Outlook, OWA, or EWS directly on a mailbox folder.
Direct Logon ApplicationAccount always ApplicationAccount always ApplicationAccount

FYI: Issue with Windows 7 RC and VSTO…

The VSTO team has a post which details an issue that you might see when trying to deploy a VSTO solution to Windows 7 RC.  The error message would be…

“The required version of the .NET Framework is not installed on this computer”

As the blog post points out, the appropriate teams are aware of the issue and plan to address it by RTM of Windows 7.  Additionally they provide a workaround in the meantime.

Posted by mstehle | 1 Comments
Filed under: ,

FYI: Exchange 2007 SP2 Announced…

The Exchange team announced the upcoming service pack for Exchange 2007 recently.  The primary focus of this service pack is preparing Exchange 2007 for interoperability with Exchange 2010 but there are also fixes and changes to existing components and technologies that make this update worth installing when it comes out.  Here are some developer related points of interest that were announced:

Exchange Volume Snapshot Backup Functionality - A new backup plug-in has been added to the product that will enable customers to create Exchange backups when a backup is invoked through the Windows Server 2008 Backup tool. Exchange Server 2007 didn't have this capability on Windows Server 2008 and additional solutions were required to perform this task.

Named Properties cmdlets - SP2 enables Exchange administrators to monitor their named property usage per database.”

…Both of these are most useful to developers as debugging tools but they are valuable nonetheless.

Posted by mstehle | 1 Comments

INFO: EWS Tips and Tricks Links…

MVP Henning Krause has some good posts about various different tips and tricks with EWS that are worth looking at…

Searching a meeting with a specific UID using Exchange Web Services 2007

Resolving the primary email address with Exchange WebServices ResolveNames operation

Saving custom data on Exchange elements with The Exchange WebServices

…The UID and custom data posts are particularly insightful.  A key takeaway of the UID post is that “schema properties” or “first-class properties” such as UID often are calculated from or directly relate to “extended properties” or “MAPI properties”.  Often times you can workaround a limitation of schema properties by using the related extended property as Henning does with UID and GlobalObjectID.  In the saving custom data post, Henning gives some good background on named properties as well as why choosing the right property set is important…

"One property set is of particular interest, namely the one called PublicStrings. All custom properties created with Outlook are stored in this set. If a custom property is designed to be used by custom Outlook formulas, the developer must choose this property set. In any other case, it is better to create a random GUID and use that property set to prevent collisions with other applications.”

Posted by mstehle | 2 Comments

FYI: In Outlook 2010 Exchange Client Extensions Are Gone…

On the Outlook team blog it was announced recently that Exchange Client Extensions (ECEs) will not work with Outlook 2010.  This shouldn’t come as a big surprise, they haven’t been a primary extensibility model for Outlook since Outlook 97-98 days.  However, many Outlook developers have continued to maintain their ECEs and Microsoft supports them to work on Outlook versions up to Outlook 2007.  Here are the suggestions from the blog post about how to move forward…

“To redesign your solution, you should consider the following options:

  • Rewrite your ECE as a COM Add-in using native or managed code. Unlike ECEs, an add-in represents a strategic extensibility technology that is fully supported in Outlook 2010. Using an Outlook add-in, you can build Outlook form regions and extend the Office Fluent User Interface. For additional information, please visit the Outlook Developer Portal on MSDN.
  • Rewrite your ECE as a Windows service application using native code and MAPI. If you are writing a Windows service application, you must use MAPI to access Outlook items rather than the Outlook object model.”

FYI: Unlike Exchange 2007, Exchange 2010 will *not* ship a 32-bit version

The Exchange team announced that Exchange 2010 will not have a 32-bit version – not even for evaluations.  The post focuses on mainly the non-developer related impact of this change.  The key points for developers are:

> Applications that automate Exchange cmdlets locally will need to be compiled for 64-bit.

> 32-bit or 64-bit applications could leverage the remote Powershell capabilities in Powershell 2.0 to invoke the Exchange cmdlets remotely.

FYI: The Exchange Web Services Managed API is here!

As you might have seen, we announced last week that the Exchange Web Services Managed API is now available as a beta download.  I’ve been working with the API internally for about a year now and I must say, if you are writing .NET code that uses Exchange Web Services there’s no better way to do it.  I’ve been working on an Exchange browser application, similar to MFCMAPI which started out leveraging the auto-generated proxy classes.  Switching this project over to the EWS Managed API cut down hundreds of lines of code and improved the readability and organization of the code immensely.  (Stay tuned for more information on this project…)

From David Claux’s introduction:

“The EWS Managed API is a fully object-oriented API that provides the experience developers have come to expect from Visual Studio and the Microsoft .NET Framework. Built on the EWS XML protocol, it provides an easy-to-learn, easy–to-use, and easy-to-maintain .NET interface to Exchange Web Services that both beginner and advanced developers will find to be an improvement over autogenerated proxies.

Although the EWS Managed API is a new API (in the sense that it is a new .NET assembly that developers have to explicitly reference in their applications), it is important to understand that we are not replacing the EWS protocol. The EWS Managed API is just a complement to EWS for .NET developers. This means that your prior investments are safe. Whether you are using raw XML (if you are a Javascript developer, for example) or autogenerated proxies (on Windows or other operating systems) to talk to EWS, your existing EWS applications will continue to work. The EWS protocol is still the future of Exchange development; all new features will continue to be added to the EWS protocol, and will also be exposed in the EWS Managed API.”

The API at it’s simplest is just a set of proxy classes for interacting with Exchange – they still generate the same Exchange Web Services SOAP XML that the auto-generated proxy classes do or that your code that doesn’t use proxy classes do.  The difference is that this API is easy to use, understand, and has some additional business logic included.  The release of this API doesn’t change the support or our recommendations towards use of Exchange Web Services in their raw form.

Here are Matt’s three rules for getting started:

  1. Check out David Claux’s introduction for the API on MSDN as well as the “Working with…” section of the MSDN reference.
  2. Don’t confuse the Exchange Web Services Managed Reference with the EWS Managed API Reference.  The Exchange Web Services Managed Reference in the MSDN is reference of the auto-generated proxy classes.
  3. For the sake of my sanity please don’t start calling this the EWS MAPI – it’s the EWS Managed API, the EWS API, the EWS Client API, The API, Managed EWS, anything you want that doesn’t involve acronyms shared with other Exchange APIs.  (I guess I should be happy they didn’t call it EWS CDO, right?)

OOM.NET: Like a good standup comic – use scope and have good timing…

Recently, I was helping someone with a Outlook item leak type issue involving a Task FormRegion.  The symptom was that after opening a task, closing it, and reopening the item they were getting the infamous error message, “COM object that has been separated from its underlying RCW cannot be used.”  They were familiar with some of the issues discussed here and knew to call ReleaseCOMObject() on objects as they were done with them.  However, that is the only part of proper Outlook coding with .NET – you need to use scope and have good timing when you lay out .NET classes that handle events and use Outlook objects.  The following class is a simple example of that scope and timing…

Scope

As I pointed out in my original OOM.NET post, you need to consider the scope of the objects whose events you listen to.  The key is not to call ReleaseCOMObject() on an item while you are still listening to events from it.  In the class below, notice that _task is defined at the module level so that as long as the instance of TaskRegion is alive and listening to the Write() event _task will not go out of scope and get garbage collected by the CLR. 

Timing

It seems like there is a general understanding now that Outlook objects need to be released.  Additionally, you must *always decrement the event handlers that you add*.  However, the humor in a good joke is not just the punch line but also good timing – you have to be strategic about when to call ReleaseCOMObject() and when to decrement the event handler.  Since this is a FormRegion class I’m utilizing the FormRegionShowing event to initialize _task and add the event handler and I use FormRegionClosed to remove the event handler and release _task.  In a simple item wrapper class you might use the constructor and a dispose method in the same way.  The goal is not call ReleaseCOMObject() until the events are unhooked, that way the COM object become separated from your RCW that is still trying to handle events.

NOTE – I’m also employing Patrick’s fix in FormRegionInitializing for a FormRegion specific leak scenario…

partial class TaskRegion
{
    Outlook.TaskItem _task = null;

    #region Form Region Factory

    [Microsoft.Office.Tools.Outlook.FormRegionMessageClass
        (Microsoft.Office.Tools.Outlook.FormRegionMessageClassAttribute.Task)]
    [Microsoft.Office.Tools.Outlook.FormRegionName
        ("ReleaseTaskRegion.TaskRegion")]
    public partial class TaskRegionFactory
    {
        // Occurs before the form region is initialized.
        // To prevent the form region from appearing, set e.Cancel to true.
        // Use e.OutlookItem to get a reference to the current Outlook item.
        private void TaskRegionFactory_FormRegionInitializing(object sender,
            Microsoft.Office.Tools.Outlook.FormRegionInitializingEventArgs e)
        {
            Marshal.ReleaseComObject(e.OutlookItem);
        }
    }

    #endregion

    // Occurs before the form region is displayed.
    // Use this.OutlookItem to get a reference to the current Outlook item.
    // Use this.OutlookFormRegion to get a reference to the form region.
    private void TaskRegion_FormRegionShowing(object sender, System.EventArgs e)
    {
        _task = this.OutlookItem as Outlook.TaskItem;

        _task.Write += new Outlook.ItemEvents_10_WriteEventHandler(_task_Write);
    }

    private void _task_Write(ref bool Cancel)
    {
        System.Diagnostics.Debug.WriteLine("Write fired!");
    }

    // Occurs when the form region is closed.
    // Use this.OutlookItem to get a reference to the current Outlook item.
    // Use this.OutlookFormRegion to get a reference to the form region.
    private void TaskRegion_FormRegionClosed(object sender, System.EventArgs e)
    {
        _task.Write -= new Outlook.ItemEvents_10_WriteEventHandler(_task_Write);

        System.Runtime.InteropServices.Marshal.ReleaseComObject(_task);
    }
}

…This post is a continuation of my efforts to document common issues I’ve seen when .NET programmers write solutions with Outlook’s object model – be they separate executables, VSTO Add-ins, or Outlook FormRegions. To see all the posts in this series check out my posts with the OOM.NET tag…

…To check out more blog posts from Microsoft’s Messaging Developer Support team which supports Outlook, Exchange, and other email-related development using Microsoft APIs check out the DevMsgTeam tag across all MSDN blogs…

More Posts Next page »
 
Page view tracker