none
Increasing the Lifetime element for EWS Streaming Subscription Connection RRS feed

  • Question

  • Using Microsoft's EWS, we're able to listen to a mailbox and take actions when a new email comes in. However, I can't figure out how to avoid the connection timing out.

    Per the documentation, here is the constructor for a StreamingSubscriptionConnection:

    public StreamingSubscriptionConnection ( 
       
    ExchangeService service, 
       
    int lifetime 
    ) 

    In my app, I've coded it as follows:

    service = new ExchangeService(ExchangeVersion.Exchange2010_SP1); 
    StreamingSubscriptionConnection conn = new StreamingSubscriptionConnection(service, 30); 

    In other words, I've got the timeout (lifetime) set to 30 minutes, because that's the highest I've been able to set it. How can I increase this? Or, how can I trick this subscription into staying alive, even if ~45 minutes transpire between incoming emails?

    Thursday, June 16, 2011 6:58 PM

Answers

  • I solved this by doing the following (Run is the main entry point):

     

    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using Microsoft.Exchange.WebServices.Data;
    
    public class InboxMonitor
    {
     private readonly EventWaitHandle NotificationsEnded = new EventWaitHandle(false, EventResetMode.ManualReset);
     private readonly EventWaitHandle ShutdownEvent = new EventWaitHandle(false, EventResetMode.ManualReset);
    
     private void ProcessEmails(ExchangeService service, IEnumerable<EmailMessage> emails)
     {
      // process your emails here...
     }
    
     public void Run(ExchangeService service)
     {
      var waitHandles = new[] { NotificationsEnded, ShutdownEvent };
      StreamingSubscriptionConnection streamingSubscriptionConnection = null;
    
      while (!ShutdownEvent.WaitOne(0))
      {
       streamingSubscriptionConnection = SetStreamingNotifications(service);
       FindItemsResults<Item> items = null;
    
       while ((items = service.FindItems(WellKnownFolderName.Inbox, new ItemView(100, 0))).TotalCount > 0)
       {
        var emailItems = items.OfType<EmailMessage>();
        if (emailItems.FirstOrDefault() != null)
         ProcessEmails(service, emailItems);
       }
    
       WaitHandle.WaitAny(waitHandles);
      }
    
      if (streamingSubscriptionConnection != null && streamingSubscriptionConnection.IsOpen)
       streamingSubscriptionConnection.Close();
     }
    
     public void Shutdown()
     {
      ShutdownEvent.Set();
     }
    
    
     StreamingSubscriptionConnection SetStreamingNotifications(ExchangeService service)
     {
      var streamingSubscription = service.SubscribeToStreamingNotifications(
       new FolderId[] {WellKnownFolderName.Inbox},
       EventType.NewMail);
    
      var connection = new StreamingSubscriptionConnection(service: service, lifetime: 10 /* 10 minutes */);
    
      connection.AddSubscription(streamingSubscription);
    
    
      connection.OnNotificationEvent += new StreamingSubscriptionConnection.NotificationEventDelegate(OnEvent);
      connection.OnSubscriptionError += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnError);
      connection.OnDisconnect += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnDisconnect);
      connection.Open();
    
      NotificationsEnded.Reset();
    
      return connection;
     }
    
     private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
     {
      NotificationsEnded.Set();
     }
    
     private void OnEvent(object sender, NotificationEventArgs args)
     {
      var messages = (from msg in args.Events.OfType<ItemEvent>()
          select EmailMessage.Bind(args.Subscription.Service, msg.ItemId));
    
      if (messages.FirstOrDefault() != null)
       ProcessEmails(args.Subscription.Service, messages);
     }
    
     private static void OnError(object sender, SubscriptionErrorEventArgs args)
     {
      var connection = (StreamingSubscriptionConnection)sender;
    
      if (connection != null)
       connection.Close();
     }
    }


    My SetStreamingNotifications method sets up the subscription as you have done above, but also subscribes to the OnDisconnect event.  The handler for the OnDisconnect event signals the NotificationsEnded event.  The event gets Reset in SetStreamingNotifications.

     

    Also you may notice a race condition above when an email comes in after the subscriptions are setup and before the call to FindItems.  This is handled in my method ProcessEmails to ensure that processing only happens once.




    • Edited by Paul W. Coleman Friday, June 17, 2011 11:18 AM
    • Marked as answer by wefx Monday, June 27, 2011 2:31 PM
    Thursday, June 16, 2011 8:15 PM

All replies

  • I solved this by doing the following (Run is the main entry point):

     

    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using Microsoft.Exchange.WebServices.Data;
    
    public class InboxMonitor
    {
     private readonly EventWaitHandle NotificationsEnded = new EventWaitHandle(false, EventResetMode.ManualReset);
     private readonly EventWaitHandle ShutdownEvent = new EventWaitHandle(false, EventResetMode.ManualReset);
    
     private void ProcessEmails(ExchangeService service, IEnumerable<EmailMessage> emails)
     {
      // process your emails here...
     }
    
     public void Run(ExchangeService service)
     {
      var waitHandles = new[] { NotificationsEnded, ShutdownEvent };
      StreamingSubscriptionConnection streamingSubscriptionConnection = null;
    
      while (!ShutdownEvent.WaitOne(0))
      {
       streamingSubscriptionConnection = SetStreamingNotifications(service);
       FindItemsResults<Item> items = null;
    
       while ((items = service.FindItems(WellKnownFolderName.Inbox, new ItemView(100, 0))).TotalCount > 0)
       {
        var emailItems = items.OfType<EmailMessage>();
        if (emailItems.FirstOrDefault() != null)
         ProcessEmails(service, emailItems);
       }
    
       WaitHandle.WaitAny(waitHandles);
      }
    
      if (streamingSubscriptionConnection != null && streamingSubscriptionConnection.IsOpen)
       streamingSubscriptionConnection.Close();
     }
    
     public void Shutdown()
     {
      ShutdownEvent.Set();
     }
    
    
     StreamingSubscriptionConnection SetStreamingNotifications(ExchangeService service)
     {
      var streamingSubscription = service.SubscribeToStreamingNotifications(
       new FolderId[] {WellKnownFolderName.Inbox},
       EventType.NewMail);
    
      var connection = new StreamingSubscriptionConnection(service: service, lifetime: 10 /* 10 minutes */);
    
      connection.AddSubscription(streamingSubscription);
    
    
      connection.OnNotificationEvent += new StreamingSubscriptionConnection.NotificationEventDelegate(OnEvent);
      connection.OnSubscriptionError += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnError);
      connection.OnDisconnect += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnDisconnect);
      connection.Open();
    
      NotificationsEnded.Reset();
    
      return connection;
     }
    
     private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
     {
      NotificationsEnded.Set();
     }
    
     private void OnEvent(object sender, NotificationEventArgs args)
     {
      var messages = (from msg in args.Events.OfType<ItemEvent>()
          select EmailMessage.Bind(args.Subscription.Service, msg.ItemId));
    
      if (messages.FirstOrDefault() != null)
       ProcessEmails(args.Subscription.Service, messages);
     }
    
     private static void OnError(object sender, SubscriptionErrorEventArgs args)
     {
      var connection = (StreamingSubscriptionConnection)sender;
    
      if (connection != null)
       connection.Close();
     }
    }


    My SetStreamingNotifications method sets up the subscription as you have done above, but also subscribes to the OnDisconnect event.  The handler for the OnDisconnect event signals the NotificationsEnded event.  The event gets Reset in SetStreamingNotifications.

     

    Also you may notice a race condition above when an email comes in after the subscriptions are setup and before the call to FindItems.  This is handled in my method ProcessEmails to ensure that processing only happens once.




    • Edited by Paul W. Coleman Friday, June 17, 2011 11:18 AM
    • Marked as answer by wefx Monday, June 27, 2011 2:31 PM
    Thursday, June 16, 2011 8:15 PM
  • Where does NotificationsEnded get defined?
    Thursday, June 16, 2011 8:30 PM
  • NotificationsEnded, like ShutdownEvent, is a property on a class.  The code above is in a method on the same class.  SetStreamingNotifications is also a method on the same class.

     

    Specifcally, Notifications is defined as:

    private EventWaitHandle NotificationsEnded = new EventWaitHandle(false, EventResetMode.Manual);
    
    

    Thursday, June 16, 2011 11:42 PM