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

4
我有一个用EWS managed api (v2.2)创建的应用程序,可以通知我新邮件的到来。我使用StreamingSubscription来监听邮箱事件。我注意到有时候NewMail事件没有被触发(我稍后在邮箱中看到未处理的邮件),并且没有连接/订阅异常被抛出,在一段时间之后,新邮件的接收就像什么也没发生一样...是什么原因导致了这种行为?交换日志中没有可疑的东西,事件就是没有被触发...有什么想法和建议吗?
谢谢。
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;
        }
    }
}
1个回答

6
我认为我可以自己回答这个问题 - 要保证持续工作,您需要更新订阅。但是这里的奇怪之处在于:没有抛出异常(在OnDisconnect事件处理程序的SubscriptionErrorEventArgs中有一个异常对象:

无法检索此订阅的事件。必须重新创建订阅。

当您在不会收到订阅事件通知的情况下超时,一段时间后,您将继续使用旧订阅接收事件通知...。 更新: 我最终采用的解决方案是:如果OnDisconnect事件中的SubscriptionErrorEventArgs不包含异常,则简单地打开关闭的连接,否则引发Disconnected事件,并让父类决定是否尝试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;
        }
    }
}

那么你是如何更新订阅的呢?是在OnDisconnect处理程序内部还是使用单独的计时器?您介意发布一下您所做的更改以使其正常工作的代码吗? - 1.618
我也很想看看您如何更新订阅。能否发布一下代码? - Mike Ribeiro
@MikeRibeiro 我之前发布过这段代码-如原答案更新所述: 我最终采用的解决方案是:如果OnDisconnect事件中的SubscriptionErrorEventArgs不包含异常-简单地打开关闭的连接,否则-引发Disconnected事件,并让父类决定-是否应尝试重新连接(通过调用Reconnect)。 - da_sann
如何安排此应用程序进行监控? - vijay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接