Notifications - Push, Pull, Stream Notification #3


 Exchange 2013을 기반으로 개발을 진행하면서 맞닥뜨리게 된 케이스에 대해서 공유 하고자 한다. 이전에 잠깐 EWS(Exchange Web Service)를 통해 간단한 기능을 사용해본 경험이 전부라서 하나의 기능을 구현하기 위해 여러가지 방안에 대해서 바위에 계란치기로 직접 부딪혀 볼 수 밖에 없었다. 이런 힘들고 시간 싸움을 줄이는데 도움을 드리는데 일조 하고자 이곳에 공유 하고자 합니다. 비록 덜 정제 되고 문서 미비할 수 있지만 참고 사항으로 알아 두셨으면 합니다. 



 이번 포스트에서는 지난 시간에 다루지 못했던 프로그래머 관점에서 살펴 보고자 한다. Pull, Push, Stream 방식은 가각의 장단점이 있으니 적절히 판단하여 실 환경에 적용해야 하겠습니다. 각 장단점은 이전 포스트의 첫번째에서 비교를 해 놓았습니다.


1. Stream notifications

#region Streaming notifications test ExchangeService serviceConnection = EWSHelper.GetService();   //EWS를 반환 한다. StreamingSubscriptionConnection streamConnection = new StreamingSubscriptionConnection(serviceConnection30);  //Timeout은 1 ~ 30분, 하나의 커넥션을 만든다. FolderId[] foldersToWatch = null; StreamingSubscription streamingsubscription = null; foreach (var member in Members.GetUsers()) {     //비동기 상에서 overwrap이 되지 않도록 처리     var m = member;     var task = System.Threading.Tasks.Task.Factory.StartNew(() =>     {         Log.WriteLine(m + " : Subscription 등록중");         #region Server와 Impersonate를 진행         ExchangeService service = EWSHelper.GetService();   //GetService(member);         //가장할 사용자 정보         service.ImpersonatedUserId = new ImpersonatedUserId() { Id = mIdType = ConnectingIdType.SmtpAddress }; //구독에 필요한 정보를 세팅         StreamingSubscription streamSubscription = service.SubscribeToStreamingNotifications(                     new FolderId[] { WellKnownFolderName.Inbox },                     EventType.NewMail,                     EventType.Modified             );         //connection에 subscription를 추가하여 이벤트를 받을 수 있도록 함. //하나의 커넥션의 여러개의 Subscription을 추가한다. 기본적으로 StreamConnection은 2000를 넘으면 서버에서 Busy Exception을 발생시킨다.         streamConnection.AddSubscription(streamSubscription);         Log.WriteLine(m + " : Subscription 등록 완료");     });     tasks.Add(task); } #endregion //모든 비동기 겍체가 완료가 될때까지 대기 함. System.Threading.Tasks.Task.WaitAll(tasks.ToArray()); //Connections.TryAdd("Connection1", streamConnection); // 이벤트 등록 streamConnection.OnNotificationEvent += streamConnection_OnNotificationEvent; streamConnection.OnSubscriptionError += streamConnection_OnSubscriptionError; streamConnection.OnDisconnect += streamConnection_OnDisconnect; streamConnection.Open();

[코드1] Stream notification을 등록 요청 및 이벤트 핸들러 등록



 아래 "코드2"에서는 위에서 등록한 이벤트 핸들러에 대한 코드다.

/// <summary> /// Subscription 설정에 따른 Notification 이벤트 발생 /// </summary> /// <param name="sender"></param> /// <param name="args"></param> private void streamConnection_OnNotificationEvent(object senderNotificationEventArgs args) {     var task = System.Threading.Tasks.Task.Factory.StartNew(() =>         {             var message = string.Empty;             var id = args.Subscription.Service.ImpersonatedUserId.Id;             message = id + ";";             #region Binding된 데이터를 가지고 테스트             IEnumerable<ItemId> itemEvents = from e in args.Events.OfType<ItemEvent>()                                                 select e.ItemId;             //Item.Bind(args.Subscription.Service, itemId)   //하나의 객체에 대해서만 바인딩             var response = args.Subscription.Service.BindToItems(itemEventsnew PropertySet(BasePropertySet.IdOnlyEmailMessageSchema.From));             var items = response.Select(itemResponse => itemResponse.Item);             foreach (var item in items)             {                 EmailMessage msg = item as EmailMessage;                 if (msg != null)                 {                     message += msg.From.Address + "," + item.Id + "," + DateTime.Now.ToString() + ",watermark=" + args.Subscription.Watermark;                 }             }             #endregion 

            Log.WriteLine(message);         }); } /// <summary> /// Subscription 관련 에러 이벤트 발생 /// </summary> /// <param name="sender"></param> /// <param name="args"></param> void streamConnection_OnSubscriptionError(object senderSubscriptionErrorEventArgs args) {              } /// <summary> /// Subscription Connection 설정 시간(최대 30분)이 지나서 Disconnect 이벤트 발생하면,  Connection 재 연결 처리 /// </summary> /// <param name="sender"></param> /// <param name="args"></param> void streamConnection_OnDisconnect(object senderSubscriptionErrorEventArgs args) {     StreamingSubscriptionConnection connection = (StreamingSubscriptionConnection)sender;                  if (connection != null)     {         if (!connection.IsOpen)         {             //Connection이 끊어지면 다시 오픈하여 이벤트를 받을 수 있도록 함.             connection.Open();         }     } }

[코드2] 이벤트 핸들러


 위 코드에서 streamConnection_OnDisconnection 이벤트는 StreamConnection이 Timeout인해(등록시 30분으로 세팅하여 연결하였고 30분 지나면 OnDisconnection 발생 후 종료 한다) 연결이 끊어진다. 그래서 이 이벤트가 발생하면 계속 유지가 되도록 코딩이 되어 있다. OnNotificationEvent는 일반적인 시나리오에서 발생하는 이벤트이며 이곳에서 아이템에 대한 상태를 판단할 수 있다. 그리고 더 많은 정보를 가져오기 위해서는 Bind를 통해서 한번 더 서버에 접근해야 추가 정보를 가져올 수 있다.












Exchange flow diagram V1.pptx


+ Recent posts