5

我正在尝试创建一个服务来将交换通知推送到 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 + "-------------");
        }
    }
}
4

1 回答 1

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); 从服务中提取流订阅的位置。

于 2013-04-30T08:20:17.800 回答