asp.net - 多个用户的 EWS 通知中心

标签 asp.net exchange-server exchangewebservices signalr-hub

我正在尝试创建一个服务来将交换通知推送到 asp.net 应用程序,最终使用 SignalR。

我的计划是创建一个通知中心,在每个用户登录到 asp 应用程序并为他们监听通知时订阅他们。收到通知后,项目的第二部分是使用 signalR 仅向每个用户发送正确的通知。一旦他们注销或超时,通知中心将取消订阅他们。

到目前为止,我已经完成了一些基本测试,并且可以使用硬编码的凭据在一个小型控制台应用程序中为自己接收通知。我正在努力解决的是如何同时为多人做到这一点。例如,我是否必须为每个用户创建单独的线程,还是有更好的方法?

我想无论如何我都必须使用模拟而不是持有每个用户的凭据吗?如果每个用户有事件 session ,我还必须想出一种方法来自动刷新每个用户的超时时间。

下面是我发现并一直在使用的一些小代码,我将不胜感激任何人可以分享我如何最好地实现这一目标的任何想法或示例。

非常感谢

安迪

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Exchange.WebServices.Data;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

                ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
                service.Url = new Uri("https://server/EWS/Exchange.asmx");
                service.Credentials = new NetworkCredential("user", "pass", "domain");
                SetStreamingNotifications(service); 
                while (true)
                { }


        }

        static void SetStreamingNotifications(ExchangeService service)
        {
            // Subscribe to streaming notifications on the Inbox folder, and listen
            // for "NewMail", "Created", and "Deleted" events.
            StreamingSubscription streamingsubscription = service.SubscribeToStreamingNotifications(
                new FolderId[] { WellKnownFolderName.Calendar, WellKnownFolderName.Inbox },
                EventType.Created,
                EventType.Modified);

            StreamingSubscriptionConnection connection = new StreamingSubscriptionConnection(service, 9);

            connection.AddSubscription(streamingsubscription);
            // Delegate event handlers.
            connection.OnNotificationEvent +=
                new StreamingSubscriptionConnection.NotificationEventDelegate(OnEvent);
            connection.OnSubscriptionError +=
                new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnError);
            connection.OnDisconnect +=
                new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnDisconnect);
            connection.Open();

            Console.WriteLine("--------- StreamSubscription event -------");
        }

        static private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
        {
            // Cast the sender as a StreamingSubscriptionConnection object.          
            StreamingSubscriptionConnection connection = (StreamingSubscriptionConnection)sender;
            // Ask the user if they want to reconnect or close the subscription.
            ConsoleKeyInfo cki;
            Console.WriteLine("The connection to the subscription is disconnected.");
            Console.WriteLine("Do you want to reconnect to the subscription? Y/N");
            while (true)
            {
                cki = Console.ReadKey(true);
                {
                    if (cki.Key == ConsoleKey.Y)
                    {
                        connection.Open();
                        Console.WriteLine("Connection open.");
                        break;
                    }
                    else if (cki.Key == ConsoleKey.N)
                    {
                        // The ReadKey in the Main() consumes the E.
                        Console.WriteLine("\n\nPress E to exit");
                        break;
                    }
                }
            }
        }

        static void OnEvent(object sender, NotificationEventArgs args)
        {
            StreamingSubscription subscription = args.Subscription;

            // Loop through all item-related events.
            foreach (NotificationEvent notification in args.Events)
            {

                switch (notification.EventType)
                {
                    case EventType.NewMail:
                        Console.WriteLine("\n-------------Mail created:-------------");
                        break;
                    case EventType.Created:
                        Console.WriteLine("\n-------------Item or folder created:-------------");
                        break;
                    case EventType.Deleted:
                        Console.WriteLine("\n-------------Item or folder deleted:-------------");
                        break;
                }
                // Display the notification identifier.
                if (notification is ItemEvent)
                {
                    // The NotificationEvent for an e-mail message is an ItemEvent.
                    ItemEvent itemEvent = (ItemEvent)notification;
                    Console.WriteLine("\nItemId: " + itemEvent.ItemId.UniqueId);

                }
                else
                {
                    // The NotificationEvent for a folder is an FolderEvent.
                    //FolderEvent folderEvent = (FolderEvent)notification;
                    //Console.WriteLine("\nFolderId: " + folderEvent.FolderId.UniqueId);
                }
            }
        }
        static void OnError(object sender, SubscriptionErrorEventArgs args)
        {
            // Handle error conditions.
            Exception e = args.Exception;
            Console.WriteLine("\n-------------Error ---" + e.Message + "-------------");
        }
    }
}

最佳答案

我解决这个问题的方法是:

  • 拥有一个有权模拟所有用户的帐户。
  • 我为该帐户创建了一个服务,并提供了一个用户名和
    密码。
  • 我模拟一个用户并将用户的订阅添加到
    连接
  • 我创建了另一个服务,它是主要服务的关闭
    相同的用户名和密码,这将冒充另一个用户
    然后将订阅添加到
  • 之前的同一连接中

    这是我的代码的两部分。忘记 LogDevice 它只是内部的东西。
    第一部分是详细的模拟和将服务添加到服务列表中
    在我的情况下,服务列表是一个字典,其中 userSMTP 是键,这里的 UserSMTP 键是模拟帐户。
        /// <summary>
        /// Impersonate one user at a time and without using the autodiscovery method to find the proper url for the userSmtp, 
        /// and copy the provided url to the usersmtp.
        /// </summary>
        /// <param name="url"> </param>
        /// <param name="userSmtp">user smtp</param>
        /// <param name="enableTrace">to enable logging from the XML tracing </param>
        /// <param name="exchangeVersion">Exchange server version used</param>
        private Uri ImpersonateUser(Uri url, string userSmtp, bool enableTrace, ExchangeVersion exchangeVersion)
        {
            Uri result = url;
            var log = "ImpersonateUser \n";
            try
            {
                log += "0/8 Checking services redundancy\n";
                if (Services.ContainsKey(userSmtp))
                {
                    Services.Remove(userSmtp);
                }
                log += "1/8 Create a new service for " + userSmtp + "\n";
                var service = new ExchangeService(exchangeVersion);
    
                log += "2/8 Get credentials for the service\n";
                var serviceCred = ((System.Net.NetworkCredential)(((WebCredentials)(Services.First().Value.Credentials)).Credentials));
    
                log += "3/8 Assign credentials to the new service\n";
                service.Credentials = new WebCredentials(serviceCred.UserName, serviceCred.Password);
    
                log += "4/8 TraceEnabled is" + enableTrace.ToString() + "\n";
                service.TraceEnabled = enableTrace;
    
                log += "5/8 Get the Url for the  service with AutodiscoverUrl \n";
                service.Url = url;
    
                log += "6/8 Assign a new ImpersonatedUserId to the new service for" + userSmtp + "\n";
                service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, userSmtp);
    
                try
                {
                    log += "7/8 Validating the impersonation\n";
                    RuleCollection rulecoll = service.GetInboxRules();
                }
                catch (Exception ex)
                {
                    _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUser: failed to validate the impersonation for {0}\n Exception: {1}\n", userSmtp, ex.Message);
                    int hr = System.Runtime.InteropServices.Marshal.GetHRForException(ex);
    
                    if (hr == -2146233088) // We do not have right to impersonate this user.
                    {
                        result = null;
                        return result;
                    }
                    else
                    {
                        _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUser(2): trying to resolve {0} with Autodiscover instead...", userSmtp);
                        result = ImpersonateUser(userSmtp, enableTrace, exchangeVersion);
                    }
    
                }
    
                log += "8/8 Adding the service \n";
                if (!Services.ContainsKey(userSmtp))
                {
                    Services.Add(userSmtp, service);
                    _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUser(2): {0} has been impersonated\n", service.ImpersonatedUserId.Id);
                }
            }
            catch (Exception ex)
            {
                _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUser(2): exception {0}\n The exception occured after the following steps: \n{1}", ex.Message, log);
            }
            return result;
        }
    

    这是调用前一个函数的代码(即对于所有用户),请记住,您应该以某种方式存储要模拟的每个帐户的电子邮件地址。
    /// <summary>
            /// To Impersonate users in order to get the info from them. 
            /// </summary>
            /// <param name="userSmtps">List of users to be impersonated</param>
            /// <param name="enableTrace"> To enable logging from the XML tracing</param>
            /// <param name="exchangeVersion">Exchange server version used </param>
            public void ImpersonateUsers(ICollection<string> userSmtps)
            {
                var log = "ImpersonateUsers\n";
                var firstUserSmtp = "";
                if (userSmtps != null)
    
                    if (userSmtps.Count > 0)
                    {
    
                        //the url for the first smtp
                        try
                        {
                            log += "1/2 Impersonating the first userSmtp\n";
                            _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUsers:  Getting the Url from the autodiscovery for the first smtp {0} ", userSmtps.First());
                            bool enableTrace = Services.First().Value.TraceEnabled;
    
                            ExchangeVersion exchangeVersion = Services.First().Value.RequestedServerVersion;
                            firstUserSmtp = userSmtps.First();
                            var commonSmtpUrl = ImpersonateUser(userSmtps.First(), enableTrace, exchangeVersion);
                            if (commonSmtpUrl == null) userSmtps.Remove(firstUserSmtp);
                            // If the list contains other than the first one 
                            log += "2/2 Impersonating " + (userSmtps.Count - 1) + " userSmtps\n";
    
                            if (userSmtps.Count >= 1)
                            {
                                foreach (var userSmtp in userSmtps)
                                {
                                    try
                                    { //skip ther first one because it is already impersonated. 
                                        if (userSmtp == firstUserSmtp)
                                        {
                                            continue;
                                        }
                                        // Impersonate the users
                                        _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUsers:  Impersonating {0} ...", userSmtp);
    
                                            commonSmtpUrl = ImpersonateUser(userSmtp, enableTrace, exchangeVersion);
    
                                    }
                                    catch (Exception ex)
                                    {
                                        _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUsers: Impersonating {1}\n exception {0}\n", ex.Message, userSmtp);
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            _logDevice.LogSrvMessage(1, "ExchangeLiteService: ImpersonateUsers: exception {0}\n The exception occured after the following steps: \n{1}", ex.Message, log);
                        }
                    }
            }
    

    我本来会把订阅部分添加到连接中,但它有点丑陋且难以获得。但这个想法很简单,你应该有一个连接,然后你去你所做的每一个服务,然后`connection.AddSubscription(streamingSubscription);
    从服务中提取流订阅的地方。

    关于asp.net - 多个用户的 EWS 通知中心,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16232341/

    相关文章:

    c# - 我无法使用 Visual Studio 2019 中的 Google Cloud Platform 工具将 App Engine 应用程序发布到 GCloud

    java - 有没有办法将系统剪贴板中的文件作为附件粘贴到 MS Exchange 的电子邮件中?

    javascript - 如何在我的 Web 应用程序中检索和显示 Outlook/Exchange 日历事件?

    java - 从哪里可以获得 EWS JAVA API 2.0?

    c# - 如何在没有邮箱的情况下使用具有 Windows 身份验证和身份的 EWS 发送和保存电子邮件?

    php - 未捕获的 soapfault 异常

    java - 交换 web 服务错误 : the request failed. 空

    c# - 在 GridView 中为复选框列生成新列

    asp.net - SyndicationFeed : Content as CDATA?

    asp.net - 由于 FIPS 140 安全策略,ASPX 页面失败