10

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 Microsoft, 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?

WEFX
  • 8,298
  • 8
  • 66
  • 102

3 Answers3

17

30 minutes is a hard limit. You can not change it to a higher value.

To solve this issue, wire up a handler to the OnDisconnected handler of the OnDisconnect event of the connection instance. Restart the subscription from there (just call connection.Open() from that handler).

Henning Krause
  • 5,302
  • 3
  • 24
  • 37
  • But what about when it's a legitimate disconnect? For example, somebody stops the service... I would need to distinguish between the two scenarios. – WEFX Jun 27 '11 at 13:24
  • Ah, I see now. A "Stop" is considered different from a Disconnect. I'll take it. Thanks – WEFX Jun 27 '11 at 14:26
  • Let me test this a bit, and the bounty will be yours, @Henning Krause. – WEFX Jun 27 '11 at 14:27
  • 1
    what happens if a new mail arrives just between the disconnect notification and re-connect call? will I miss the notification of that mail? thank you – DayDayHappy Jun 02 '16 at 06:17
  • After reestablishing the connection you can just manually do a SyncFolderItems request to get any missed events which occured during that timeframe. – Henning Krause Aug 16 '16 at 15:58
  • One minor point that I've experienced: The OnDisconnect event handler method is apparently called on a thread pool thread, so you may need to be careful of multi-threading considerations. – RenniePet Oct 14 '17 at 03:51
2

If anyone else is interested, this is how I am accomplishing this.

I want to keep the connection open, so I am resetting it in the OnDisconnect handler.

However, before resetting it, I check the private "subscriptions" dictionary on the connection object using reflection.

This allows me to unsubscribe from my connections elsewhere in my code (OnNotificationEvent), and when all subscriptions have been unsubscribed from, I am then able to close the connection.

Here is my Code:

 void connection_OnDisconnect(object sender, SubscriptionErrorEventArgs args)
    {
        var c = (Dictionary<string, StreamingSubscription>)typeof(StreamingSubscriptionConnection).GetField("subscriptions",System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(sender);

        if (c.Count > 0)
        {
            // reopen the connection
            ((StreamingSubscriptionConnection)sender).Open();

            using (var db = new Metrics_DatabaseEntities())
            {
                PushNotificationTest pt = new PushNotificationTest();
                pt.RetObj = "Connection reset";

                db.PushNotificationTests.Add(pt);

                db.SaveChanges();

            }
        }
        else
        {
            using (var db = new Metrics_DatabaseEntities())
            {
                PushNotificationTest pt = new PushNotificationTest();
                pt.RetObj = "Connection closed!";

                db.PushNotificationTests.Add(pt);

                db.SaveChanges();

            }
        }
    }

Please disregard the poor way that this is written, this is just my first version, as I plan to write this more cleanly soon. I just thought I would share my methodology with folks that might be interested.

Stevio54
  • 21
  • 1
1

If people are interested, here's the little bit of logic that got added.

I added this to my Start method:

conn.OnDisconnect += 
    new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnDisconnect);

I then added the OnDisconnect method:

private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
{
    Start();
}

Ultimately, this still needs improved, because this simply times-out and reconnects every half-hour, regardless of incoming email activity. I'd rather get something in place that resets the counter every time a new message comes in. Then, it would only time-out a couple times per day, instead of 48! Still, this is serving its purpose of keeping my email-listening program online.

WEFX
  • 8,298
  • 8
  • 66
  • 102
  • Does your OnStart method not require string[] args as a parameter – JsonStatham Sep 22 '16 at 10:38
  • 3
    You're not showing the contents of your Start() method, but what you're doing gives me bad feelings. I fear that you're creating 48 StreamingSubscriptionConnection objects every day, and that they can't be garbage-collected because they have an event handler method linked to them. So you probably have a memory leak. A very small one, in the larger scheme of things, but still ... – RenniePet Oct 14 '17 at 03:44