3

在 EWS 中运行多个用户模拟时遇到问题,当我想在每个模拟人日历(可能 100 人)上接收通知时。

目前我有一个有权模拟所有其他用户的 Outlook 帐户,并且所有 ExchangeService 对象都获得此帐户凭据

简短的版本是,当我尝试通过唯一 ID 绑定到约会时,只要我只有一个线程在运行,它就可以工作。当我启动一个包含具有自己订阅的新 Exchangeservice 的新线程时,我没有收到任何关于 Appointment.Bind()-request 的响应。

当我运行我的程序的两个实例时,每个实例只有一个线程,它工作正常,但是一旦我使用新的 ExchangeService 启动一个新线程,Appointment.Bind() 就不会给出任何响应。

奇怪的是,两周前它运行良好,但突然停止运行,我没有更改我的代码。

我创建了一个我的问题的快速演示:

class Program
{
    static void Main(string[] args)
    {
        var x = new OutlookListener("user1@server.com");
        var y = new OutlookListener("user2@server.com");
        new Thread(x.Start).Start();
        new Thread(y.Start).Start();
        while (true)
        {

        }
    }
}
class OutlookListener
{
    private ExchangeService _ExchangeService;
    private AutoResetEvent _Signal;
    public OutlookListener(string emailToImp)
    {
        _ExchangeService = new ExchangeService(ExchangeVersion.Exchange2010_SP1)
        {
            Credentials = new NetworkCredential("superuser@server.com", "password"),
            Url = new Uri("exchangeUrl"),
            ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, emailToImp)
        };
    }
    public void Start()
    {
        var subscription = _ExchangeService.SubscribeToStreamingNotifications(new FolderId[] { WellKnownFolderName.Calendar },
                                                                  EventType.Created);
        var connection = CreateStreamingSubscription(_ExchangeService, subscription);
        Console.Out.WriteLine("Subscription created.");
        _Signal = new AutoResetEvent(false);
        _Signal.WaitOne();
        subscription.Unsubscribe();
        connection.Close();
    }

    private StreamingSubscriptionConnection CreateStreamingSubscription(ExchangeService service, StreamingSubscription subscription)                                                                         
    {
        var connection = new StreamingSubscriptionConnection(service, 30);
        connection.AddSubscription(subscription);
        connection.OnNotificationEvent += OnNotificationEvent;
        connection.OnSubscriptionError += OnSubscriptionError;
        connection.OnDisconnect += OnDisconnect;
        connection.Open();

        return connection;
    }
    private void OnNotificationEvent(object sender, NotificationEventArgs args)
    {
        // Extract the item ids for all NewMail Events in the list.
        var newMails = from e in args.Events.OfType<ItemEvent>()
                       where e.EventType == EventType.Created
                       select e.ItemId;

        foreach (var newMail in newMails)
        {
            var appointment= Appointment.Bind(_ExchangeService, newMail); //This is where I dont get a response!
            Console.WriteLine(appointment.Subject);
        }
    }
    private void OnSubscriptionError(object sender, SubscriptionErrorEventArgs args)
    {
    }
    private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
    {
    }
}

有什么建议么?

4

2 回答 2

2

我遇到了同样的问题,发现我的 EWS 解决方案受到两个因素的限制。System.Net.ServicePointManager.DefaultConnectionLimit默认设置为 2,我已将其更改为 20,我认为这与 Exchange Online 的限制策略相匹配。

其次,ExchangeService 对象上的ConnectionGroupName属性可用于将连接汇集到不同的相关组中,这些组具有与 DefaultConnectionLimit 属性一致的并发连接限制。

覆盖设置的一种方法是将 ConnectionGroupName 属性设置为您创建的每个 ExchangeService 对象的唯一值。

ExchangeService exchangeService = new ExchangeService()
{
    ConnectionGroupName = Guid.NewGuid().ToString()
};
于 2014-01-08T11:15:04.603 回答
1

为什么需要多个线程?

在我的例子中,我已经为我想模拟的每封电子邮件创建了一个基于 smtpaddress 的服务字典,并且我都订阅了它们。一切都可以在一个线程中发生,来自任何用户的所有通知都将在 OnNotificationEvent 中处理。[此代码仅显示逻辑,不完整用于完整编译和运行]

            var service = new ExchangeService(exchangeVersion);

            var serviceCred = ((System.Net.NetworkCredential)(((WebCredentials)(Services.First().Value.Credentials)).Credentials));

            service.Credentials = new WebCredentials(serviceCred.UserName, serviceCred.Password);

            service.AutodiscoverUrl(userSmtp, RedirectionUrlValidationCallback);

            service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, userSmtp);

            Services.Add(userSmtp, service);

请注意,Services.First().Value 是可以模拟所有其他用户的服务,这里它被克隆为用户的编号。

之后订阅所有服务(请注意,现在每个服务都在模拟不同的用户)

foreach (var service in Services.Values)
            {
                SubscribeToService(service);
            }

SubscribeToService 的定义如下

private void SubscribeToService(ExchangeService service)
        {

                if (service.ImpersonatedUserId == null)
                    return;
                if (service.Url == null)
                    return;

                var serviceName = service.ImpersonatedUserId.Id;


                var streamingSubscription =
                                      service.SubscribeToStreamingNotifications(new FolderId[] { WellKnownFolderName.DeletedItems, WellKnownFolderName.Calendar },
                                                    EventType.FreeBusyChanged, EventType.Moved, EventType.Created, EventType.Modified);

                if (!Connections.ContainsKey(service.Url))
                {
                    Connections.Add(service.Url, new StreamingSubscriptionConnection(service, 30));

                }
                var connection = Connections[service.Url];

                CloseConnection(connection);

                if (!_subscriptions.ContainsKey(serviceName))
                {
                    _subscriptions.Add(serviceName, streamingSubscription);
                    connection.AddSubscription(streamingSubscription);
                }

            }

        }

所有这些都可以在一个线程中发生,我希望我的回答能帮助你干杯

于 2013-01-22T10:02:43.793 回答