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

3
在运行多个用户模拟的情况下,我在EWS中遇到了问题,当我想在每个被模拟人员的日历上接收通知时(可能有100个人)。
目前,我有一个Outlook帐户,该帐户具有模拟所有其他用户的权限,并且所有ExchangeService对象都获取此帐户的凭据。
简短地说,当我尝试通过唯一ID绑定约会时,只要我只有一个线程在运行,它就可以正常工作。当我启动包含新的Exchangeservice和自己的订阅的新线程时,我不会收到任何关于Appointment.Bind()请求的响应。
当我在每个程序实例中仅使用1个线程运行两个实例时,它可以正常工作,但是一旦我启动一个新线程并使用新的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个回答

2
我曾经遇到了同样的问题,并发现我的EWS解决方案受到了两个因素的限制。 首先,System.Net.ServicePointManager.DefaultConnectionLimit默认设置为2,我已将其更改为20,这与Exchange Online的调节策略相匹配。
其次,ExchangeService对象上的ConnectionGroupName属性可用于将连接池化到不同的相关组中,这些组具有与DefaultConnectionLimit属性相 cohernet 的并发连接限制。
覆盖这些设置的一种方法是为每个创建的ExchangeService对象设置ConnectionGroupName属性的唯一值。
ExchangeService exchangeService = new ExchangeService()
{
    ConnectionGroupName = Guid.NewGuid().ToString()
};

将 System.Net.ServicePointManager.DefaultConnectionLimit 设置为 20 对我有帮助 :) - MojoDK

1

为什么需要多个线程?

在我的情况下,我已经创建了一个基于每个我想要模拟的电子邮件的smtp地址的服务字典,并订阅了它们。所有操作都可以在一个线程中完成,来自任何用户的所有通知都将在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);
                }

            }

        }

所有这些都可以在一个线程中完成,我希望我的回答能够帮到你。祝好!


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