Exchange Web服务(EWS)中的多个模拟线程

时间:2013-01-21 10:33:14

标签: service web outlook exchange-server exchangewebservices

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

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

简短版本是,当我尝试通过唯一ID绑定到约会时,只要我只有一个线程在运行,它就可以工作。当我开始一个包含新的Exchange服务的新线程及其自己的订阅时,我不会在Appointment.Bind()上收到任何响应 - 请求。

当我运行我的程序的两个实例时,每个程序只有一个线程,它工作正常,但是一旦我用新的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)
    {
    }
}

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

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

其次,ExchangeService对象上的ConnectionGroupName属性可用于将连接池连接到具有与DefaultConnectionLimit属性的并发连接cohernet限制的不同相关组。

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

ExchangeService exchangeService = new ExchangeService()
{
    ConnectionGroupName = Guid.NewGuid().ToString()
};

答案 1 :(得分: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);
                }

            }

        }

所有这一切都可以在一个单独的线程中发生,我希望我的回答能够帮到你 干杯