适用于多个用户的EWS通知中心

时间:2013-04-26 08:51:32

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

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

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

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

我想无论我是否必须使用模拟而不是持有每个用户的凭据对吗?如果他们有一个活跃的会话,我还必须找到一种方法来自动刷新每个用户的超时。

下面是我发现并且一直在玩的一些代码,如果有任何想法或示例可以分享我如何最好地实现这一点,我将不胜感激。

非常感谢

安迪

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 + "-------------");
        }
    }
}

1 个答案:

答案 0 :(得分:3)

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

  1. 拥有一个有权冒充所有用户的帐户。
  2. 我为该帐户创建了一个服务,并提供了用户名和 密码。
  3. 我冒充用户并将用户的订阅添加到 连接
  4. 我创建了另一个服务,它是主服务的关闭 相同的用户名和密码,将冒充其他用户 然后在
  5. 之前将订阅添加到同一连接

    以下是我的代码的两部分。忘记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); 其中streamingSubscription是从服务中提取的。