EWS Notification Center for Multiple Users

I am trying to create a service for sending exchange notifications in asp.net applications, eventually using SignalR.

My plan is to create a notification center that subscribes to each user when they log in to the asp application and listen to the notifications for them. As soon as a notification is received, the second part of the project should then use signalR to send the correct notifications to each user. As soon as they log out or time out, the notification center will unsubscribe.

So far I have done some basic testing and can receive notifications in a small console application for myself with my hard-coded credentials. What I'm struggling with is how to do this for several people at once. For example, should I create separate threads for each user, or is there a better way?

I assume that I will have to use impersonation and not maintain each user's credentials correctly? I will also have to devise a way to automatically update the timeout for each user if they have an active session.

Below is a small code that I found and played with it, I would be grateful for any ideas or examples that could tell about how I could achieve this.

Many thanks

Andy

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

:

  • , .
  • .
  • , ,

. 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); .

+3

All Articles