You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EWS API多流订阅场景下如何识别日历变更事件对应的SMTP账号

问题根因

你复用了同一个ExchangeService实例创建多个订阅,每次修改ImpersonatedUserId属性都会覆盖实例内的存储值,两个StreamingSubscriptionConnection关联的都是同一个service实例,最终保存的是最后设置的user2@mydomain.com,事件触发时读取到的自然都是同一个ID。

解决方案

方案1:每个账号创建独立的ExchangeService实例(最稳妥)

不要共享service实例,每个订阅账号单独初始化自己的service,保证每个connection绑定的service的模拟账号互不影响,修改后代码如下:

static bool isRunning = true;
static void Main(string[] args)
{
    // user1单独初始化service
    var service1 = EWService();
    service1.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "user1@mydomain.com");
    var StreamingSubscription1 = service1.SubscribeToStreamingNotifications(
        new FolderId[] { WellKnownFolderName.Calendar },                
        EventType.FreeBusyChanged);
    StreamingSubscriptionConnection connection1 = new StreamingSubscriptionConnection(service1, 30);
    connection1.AddSubscription(StreamingSubscription1);
    connection1.OnNotificationEvent += OnNotificationEvent;
    connection1.OnDisconnect += OnDisconnect;
    connection1.OnSubscriptionError += OnSubscriptionError;            
    connection1.Open();

    // user2单独初始化service
    var service2 = EWService();
    service2.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "user2@mydomain.com");
    var StreamingSubscription2 = service2.SubscribeToStreamingNotifications(
        new FolderId[] { WellKnownFolderName.Calendar },  
        EventType.FreeBusyChanged);
    StreamingSubscriptionConnection connection2 = new StreamingSubscriptionConnection(service2, 30);
    connection2.AddSubscription(StreamingSubscription2);
    connection2.OnNotificationEvent += OnNotificationEvent;
    connection2.OnDisconnect += OnDisconnect;
    connection2.OnSubscriptionError += OnSubscriptionError;
    connection2.Open();

    Console.WriteLine("Waiting...");
    while (isRunning)
    {
        Thread.Sleep(1000); // 避免空转占用CPU
    }

    StreamingSubscription1.Unsubscribe();
    connection1.Close();
    StreamingSubscription2.Unsubscribe();
    connection2.Close();
}

private static void OnNotificationEvent(object sender, NotificationEventArgs args)
{
    // 直接从当前connection关联的service取模拟账号,不同实例互不影响
    var connection = (StreamingSubscriptionConnection)sender;
    var userSmtp = connection.CurrentSubscriptions.First().Service.ImpersonatedUserId.Id;
    Console.WriteLine($"Event for: {userSmtp} ");         

    foreach (var item in args.Events)
    {
        Console.WriteLine(item.EventType);
        if (item.EventType == EventType.FreeBusyChanged)
        {
            Console.WriteLine(((ItemEvent)item).ItemId);
        }
    }
}

方案2:字典映射订阅ID和账号(无需创建多个service实例)

如果你不想为每个账号创建独立service,可以提前把每个订阅的唯一ID和对应SMTP账号存储在全局字典中,事件触发时通过订阅ID查询字典即可获取对应账号:

static bool isRunning = true;
// 全局字典存储:订阅ID -> 对应SMTP账号
static Dictionary<string, string> SubscriptionAccountMap = new Dictionary<string, string>();

static void Main(string[] args)
{
    var service = EWService();

    service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "user1@mydomain.com");
    var StreamingSubscription = service.SubscribeToStreamingNotifications(
        new FolderId[] { WellKnownFolderName.Calendar },                
        EventType.FreeBusyChanged);
    // 存入映射关系
    SubscriptionAccountMap.Add(StreamingSubscription.Id, "user1@mydomain.com");
    
    StreamingSubscriptionConnection connection = new StreamingSubscriptionConnection(service, 30);
    connection.AddSubscription(StreamingSubscription);
    connection.OnNotificationEvent += OnNotificationEvent;
    connection.OnDisconnect += OnDisconnect;
    connection.OnSubscriptionError += OnSubscriptionError;            
    connection.Open();

    service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "user2@mydomain.com");
    var StreamingSubscription2 = service.SubscribeToStreamingNotifications(
        new FolderId[] { WellKnownFolderName.Calendar },  
        EventType.FreeBusyChanged);
    // 存入映射关系
    SubscriptionAccountMap.Add(StreamingSubscription2.Id, "user2@mydomain.com");

    StreamingSubscriptionConnection connection2 = new StreamingSubscriptionConnection(service, 30);
    connection2.AddSubscription(StreamingSubscription2);
    connection2.OnNotificationEvent += OnNotificationEvent;
    connection2.OnDisconnect += OnDisconnect;
    connection2.OnSubscriptionError += OnSubscriptionError;
    connection2.Open();

    Console.WriteLine("Waiting...");
    while (isRunning)
    {
        Thread.Sleep(1000);
    }

    StreamingSubscription.Unsubscribe();
    connection.Close();
    SubscriptionAccountMap.Remove(StreamingSubscription.Id);
    StreamingSubscription2.Unsubscribe();
    connection2.Close();
    SubscriptionAccountMap.Remove(StreamingSubscription2.Id);
}

private static void OnNotificationEvent(object sender, NotificationEventArgs args)
{
    // 直接通过订阅ID查字典获取对应账号
    var userSmtp = SubscriptionAccountMap[args.Subscription.Id];
    Console.WriteLine($"Event for: {userSmtp} ");         

    foreach (var item in args.Events)
    {
        Console.WriteLine(item.EventType);
        if (item.EventType == EventType.FreeBusyChanged)
        {
            Console.WriteLine(((ItemEvent)item).ItemId);
        }
    }
}

内容的提问来源于stack exchange,提问作者bmoolman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 05:39:00