EWS 交换有时不会使用 StreamingSubscription 触发 NewMail 事件

EWS exchange sometimes not firing NewMail event using StreamingSubscription

我有一个通知新邮件的应用程序,使用 EWS 托管 api (v2.2) 创建。我正在使用 StreamingSubscription 来监听邮箱事件。我注意到有时 NewMail 事件没有触发(稍后我在邮箱中看到未处理的邮件),没有引发 connection/subscription 异常,并且在一段时间后接收新邮件时什么也没发生……是什么导致了这种行为?交换日志没有任何可疑之处,事件只是没有被触发...任何想法和建议将不胜感激。

谢谢。

来源:

public class ExchangeClient : IDisposable
{
    private ExchangeService _exchange;
    private SubscriptionBase _subscription;
    private StreamingSubscriptionConnection _connection;

    private bool _disposed;
    private bool _disposing;

    public event EventHandler<ExchangeEventArgs> ExchangeEvent;

    public ExchangeClient(string userName, string password, string domain, ExchangeVersion version)
    {
        _exchange = new ExchangeService(version);
        _exchange.Credentials = new WebCredentials(userName, password);

        _exchange.AutodiscoverUrl(userName + "@" + domain);

        var ids = new FolderId[2] { new FolderId(WellKnownFolderName.Root), new FolderId(WellKnownFolderName.Inbox) };
        var events = new List<EventType>();
        events.Add(EventType.NewMail);

        _subscription = _exchange.SubscribeToStreamingNotifications(ids, events.ToArray());
        _connection = new StreamingSubscriptionConnection(_exchange, 30);
        _connection.AddSubscription((StreamingSubscription)_subscription);
        _connection.OnNotificationEvent += OnNotificationEvent;
        _connection.OnSubscriptionError += OnSubscriptionError;
        _connection.OnDisconnect += OnDisconnect;
        _connection.Open();
    }

    private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
    {
        if (!_disposing && _connection != null)
        {
            _connection.Open();
        }
    }

    private void OnSubscriptionError(object sender, SubscriptionErrorEventArgs args)
    {
        throw args.Exception;
    }

    private void OnNotificationEvent(object sender, NotificationEventArgs args)
    {
        if (_subscription != null)
        {
            if (args.Subscription.Id == _subscription.Id)
            {
                foreach (var notificationEvent in args.Events)
                {
                    switch (notificationEvent.EventType)
                    {
                        case EventType.Status:
                            break;

                        case EventType.NewMail:
                            NotificationReceived(new ExchangeEventArgs(
                            notificationEvent.EventType,
                            ((ItemEvent)notificationEvent).ItemId, ((ItemEvent)notificationEvent).ParentFolderId));
                            break;

                        default:
                            break;
                    }
                }
            }
        }
    }

    public void Disconnect()
    {
        if (_connection.IsOpen)
            _connection.Close();
    }

    private void NotificationReceived(ExchangeEventArgs e)
    {
        if (ExchangeEvent != null)
        {
            ExchangeEvent(this, e);
        }
    }

    public void Dispose()
    {
        _disposing = true;
        Dispose(_disposing);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing && !_disposed)
        {
            if (_connection != null)
            {
                if (_connection.IsOpen)
                    _connection.Close();
                _connection = null;
            }
            _exchange = null;
            _disposed = true;
        }
    }
}

我想我可以自己回答这个问题 - 为保证连续工作,您需要续订。但这是奇怪的部分:没有抛出异常(OnDisconnect 事件处理程序中的 SubscriptionErrorEventArgs 中有一个异常对象:

Unable to retrieve events for this subscription. The subscription must be recreated.

当您不会收到有关订阅事件的通知时超时,一段时间后您将继续收到旧订阅的事件通知...

更新 我最终得到的解决方案是:如果 OnDisconnect 事件中的 SubscriptionErrorEventArgs 不包含异常 - 只需打开已关闭的连接,否则 - 引发 Disconnected 事件,并让父 [​​= 27=] 决定 - 我们是否应该尝试 Reconnect(通过调用 Reconnect)。

public class ExchangeEventArgs : EventArgs
{
    public EventType Type { get; private set; }
    public ItemId ItemId { get; private set; }
    public FolderId FolderId { get; private set; }

    public ExchangeEventArgs(EventType type, ItemId itemId, FolderId folderId)
    {
        Type = type;
        ItemId = itemId;
        FolderId = folderId;
    }
}

public class ExchangeClient : IDisposable
{
    private ExchangeService _exchange;
    private SubscriptionBase _subscription;
    private StreamingSubscriptionConnection _connection;

    private bool _disposed;
    private bool _disposing;

    public event EventHandler<ExchangeEventArgs> ExchangeEvent;
    public event EventHandler<DisconnectEventArgs> Disconnected;

    public ExchangeClient(string userName, string password, string domain, ExchangeVersion version)
    {
        _exchange = new ExchangeService(version);
        _exchange.Credentials = new WebCredentials(userName, password);
        _exchange.AutodiscoverUrl(userName + "@" + domain);
        _connection = new StreamingSubscriptionConnection(_exchange, 30);

        CreateSubscription();

        _connection.OnNotificationEvent += OnNotificationEvent;
        _connection.OnSubscriptionError += OnSubscriptionError;
        _connection.OnDisconnect += OnDisconnect;
        _connection.Open();
    }

    private void CreateSubscription()
    {
        var ids = new FolderId[2] { new FolderId(WellKnownFolderName.Root), new FolderId(WellKnownFolderName.Inbox) };
        var events = new List<EventType>();
        events.Add(EventType.NewMail);
        if (_subscription != null)
        {
            ((StreamingSubscription)_subscription).Unsubscribe();
            _connection.RemoveSubscription((StreamingSubscription)_subscription);
        }
        _subscription = _exchange.SubscribeToStreamingNotifications(ids, events.ToArray());
        _connection.AddSubscription((StreamingSubscription)_subscription);
    }

    private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
    {
        if (args.Exception == null)
        {
            if (!_disposing && _connection != null)
            {
                _connection.Open();
            }
        }
        else
        {
            if (Disconnected != null)
                Disconnected(this, new DisconnectEventArgs("Exchange exception", args.Exception));
        }
    }

    public bool Reconnect()
    {
        try
        {
            if (!_disposing && _connection != null)
            {
                CreateSubscription();

                _connection.Open();

                return true;
            }
            else
                return false;
        }
        catch (Exception)
        {
            return false;
        }
    }

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

    private void OnNotificationEvent(object sender, NotificationEventArgs args)
    {
        if (_subscription != null)
        {
            if (args.Subscription.Id == _subscription.Id)
            {
                foreach (var notificationEvent in args.Events)
                {
                    switch (notificationEvent.EventType)
                    {
                        case EventType.Status:
                            break;

                        case EventType.NewMail:
                            NotificationReceived(new ExchangeEventArgs(
                            notificationEvent.EventType,
                            ((ItemEvent)notificationEvent).ItemId, ((ItemEvent)notificationEvent).ParentFolderId));
                            break;

                        default:
                            break;
                    }
                }
            }
        }
    }      

    public void Disconnect()
    {
        if (_connection.IsOpen)
            _connection.Close();
    }

    private void NotificationReceived(ExchangeEventArgs e)
    {
        if (ExchangeEvent != null)
        {
            ExchangeEvent(this, e);
        }
    }

    public void Dispose()
    {
        _disposing = true;
        Dispose(_disposing);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing && !_disposed)
        {
            if (_connection != null)
            {
                if (_connection.IsOpen)
                    _connection.Close();
                _connection = null;
            }
            _exchange = null;
            _disposed = true;
        }
    }
}