2013-04-26 47 views
5

我想創建一個服務推送交換通知到asp.net應用程序,最終使用SignalR。EWS通知中心爲多個用戶

我的計劃是創建一個通知中心,用於在每個用戶登錄到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 + "-------------"); 
     } 
    } 
} 

回答

3

我解決這個問題的方法是:

  1. 具有已經冒充所有用戶權利的帳戶。
  2. 我爲該帳戶創建了一個服務,提供用戶名和密碼爲 。
  3. 我冒充用戶和用戶的訂閱添加到 連接
  4. 我創建另一個服務,這是主要的服務密切與 相同的用戶名和密碼,這將模擬其他用戶 然後添加訂閱相同的連接前

以下是我的代碼的兩個部分。忘記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從服務中提取。

+0

非常感謝!你能說一點...所以我通過這種方式獲得了模擬計劃,以便對您的「應用程序帳戶」憑據進行硬編碼並傳入您正在模擬的電子郵件帳戶。你如何處理創建第二,第三和第100個連接?做所有的訂閱,一些最終如何作爲1連接的一部分?非常感謝,安迪 – mcinnes01 2013-04-30 18:46:56

+0

是的,你是對的,所有的訂閱都去了同一個連接,我已經修改了答案,並把我的代碼的一部分。我沒有把連接的代碼放進去,因爲它很醜陋:D 無論如何,我已經描述過我是怎麼想的。 警告我不知道這是否是推薦的方式,或者它有多安全,但至少可以工作並完成工作。 – BraveHeart 2013-05-03 09:14:48

+0

感謝BraveHeart,這非常棒,我需要設置一個模擬賬戶,所以我會盡快讓你知道,一旦有了。 – mcinnes01 2013-05-03 14:37:58