Windows Phone 72011. 5. 27. 18:43

마지막이다.

 

이제 메세지를 보낼 UI를 만들어보자 관리자를 위한 프로그램이다

 

난 그냥 쉬운 WPF로 만들었다.

 

일단 버튼 하나 만들고

 

private void ToastButton_Click(object sender, RoutedEventArgs e)
      {
          string appId = "1";
          //string baseUri = string.Format("http://localhost:19976/Notifications/GetSubscribers?appId={0}", appId);
          string baseUri = string.Format("http://192.168.10.174:6060/Notifications/GetSubscribers?appId={0}", appId);
 
          GetSubscribers(baseUri);
          
      }

 

 

private void GetSubscribers(string baseUri)
     {
         WebClient webclient = new WebClient();
         webclient.DownloadDataCompleted += new DownloadDataCompletedEventHandler(webclient_DownloadDataCompleted);
         webclient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webclient_DownloadStringCompleted);
         webclient.DownloadStringAsync(new Uri(baseUri));
     }

 

이렇게 WCF 를 호출해서 사용자 URI들을 받는다. (10명이 등록 되어 있으면 서버가 10개가 들어 있는 List를 보내줌)

 

void webclient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
       {                           
           MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(e.Result));
           DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Uri>));
           deserializedListUri = serializer.ReadObject(ms) as List<Uri>;
 
           SendToast();
       }

 

자 다운이 다 되면 List로  Deserialize 한후

 

private void SendToast()
       {
 
           HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(deserializedListUri[0]);
 
           // We will create a HTTPWebRequest that posts the toast notification to the Microsoft Push Notification Service.
           // HTTP POST is the only allowed method to send the notification.
           sendNotificationRequest.Method = "POST";
 
           // The optional custom header X-MessageID uniquely identifies a notification message. 
           // If it is present, the // same value is returned in the notification response. It must be a string that contains a UUID.
           // sendNotificationRequest.Headers.Add("X-MessageID", "<UUID>");
 
           var title = "test Title";
           var subtitle = "test SubTitle";
           // Create the toast message.
 
 
           string toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
           "<wp:Notification xmlns:wp=\"WPNotification\">" +
              "<wp:Toast>" +
                   "<wp:Text1>" + title + "</wp:Text1>" +
                   "<wp:Text2>" + subtitle + "</wp:Text2>" +
              "</wp:Toast> " +
           "</wp:Notification>";
 
           // Sets the notification payload to send.
           byte[] notificationMessage = Encoding.Default.GetBytes(toastMessage);
 
           // Sets the web request content length.
           sendNotificationRequest.ContentLength = notificationMessage.Length;
           sendNotificationRequest.ContentType = "text/xml";
           sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
           sendNotificationRequest.Headers.Add("X-NotificationClass", "2");
 
           using (Stream requestStream = sendNotificationRequest.GetRequestStream())
           {
               requestStream.Write(notificationMessage, 0, notificationMessage.Length);
           }
 
           // Send the notification and get the response.
           HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
           string notificationStatus = response.Headers["X-NotificationStatus"];
           string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
           string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
 
           // Display the response from the Microsoft Push Notification Service.  
           // Normally, error handling code would be here.  In the real world, because data connections are not always available,
           // notifications may need to be throttled back if the device cannot be reached.
 
           resultTextBlock.Text = notificationStatus + " | " + deviceConnectionStatus + " | " + notificationChannelStatus;
       }
 
이렇게 보낸다 xml 형식으로 만들어서 보내면 되며
 
상태들도 header정보를 받아서 볼수 있다.

Posted by 동동(이재동)
Windows Phone 72011. 5. 27. 18:37

자 이번에는 WCF Rest Service를 만들어 보자.

 

이것도 역시 WCF Rest Service 프로젝트 생성해서

 

[ServiceContract]
   [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
   [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
   public class Notifications
   {
       private static Dictionary<string,List<Uri>> subscribers = new Dictionary<string,List<Uri>>();
       private static object obj = new object();
 
       [WebInvoke(UriTemplate = "register?uri={uri}&appId={appId}", ResponseFormat = WebMessageFormat.Xml, Method = "GET")]
       public void Register(string uri,string appId)
       {            
           Uri channelUri = new Uri(uri, UriKind.Absolute);
           Subscribe(channelUri,appId);
       }
 
       private void Subscribe(Uri channelUri,string appId )
       {
           lock (obj)
           {
               if (subscribers.ContainsKey(appId) == false)
               {
                   subscribers.Add(appId, new List<Uri>());
               }
 
 
               if (!subscribers[appId].Exists((u) => u == channelUri))
               {
                   subscribers[appId].Add(channelUri);
               }
           }
           //OnSubscribed(channelUri, true);
       }
 
       [WebInvoke(UriTemplate = "GetSubscribers?appId={appId}", ResponseFormat = WebMessageFormat.Json, Method = "GET")]
       public List<Uri> GetSubscribers(string AppId)
       {
           return subscribers[AppId];
       }

 

귀찮아서 소스만 썻다 보면 알듯이

클라이언트가 Register 메소드를 호출하여 URI와 AppID(구분을 위해)

를 주면 그걸 그냥 List에 저장하는 형식이다.

나중에 이걸 DB로 저장하게 바꾸기만 하면 된다.



 

 

Posted by 동동(이재동)
Windows Phone 72011. 5. 27. 18:31

그냥 여러개로 나누어서 적어보았다.. ㅋㅋ 웬지 그게 더 멋있어 보여서 (헐…)

 

요즘엔 다 이렇게 하더라 ㅋㅋ

자 이제 윈폰 클라이언트 프로그램을 만들어보자..

 

일단 윈폰 프로젝트를 열고

 

private HttpNotificationChannel httpChannel;
  const string channelName = "TestAppUpdatesChannel";
  // Constructor
  public MainPage()
  {
      InitializeComponent();
 
      //Create the channel
 
      //만약 채널이 이미 있으면 
      httpChannel = HttpNotificationChannel.Find(channelName);
 
      //이벤트 등록
      if (httpChannel == null)
      {
          httpChannel = new HttpNotificationChannel(channelName, "HugeFlowAppTestService");
          httpChannel.Open();
          httpChannel.BindToShellToast();
      }           
 
      SubscribeToChannelEvents();
      SubscribeToService();
      
  }

 

채널을 등록하고 open하고 bind 한다.

bindToshellToast()는 망고버전에 나온 좋은 기능이다 더 편리해졌다 ㅋ

 

만약 이미 등록되어있다면

그냥 이벤트만 연결하고 클라이언트 URI를 서버에 전달한다.

 

private void SubscribeToChannelEvents()
       {
           httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(httpChannel_ChannelUriUpdated);
           httpChannel.ShellToastNotificationReceived += new EventHandler<NotificationEventArgs>(httpChannel_ShellToastNotificationReceived);
       }

 

이렇게 이벤트 연결하고

void httpChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
       {
           StringBuilder message = new StringBuilder();
           string relativeUri = string.Empty;
 
           message.AppendFormat("Received Toast {0}:\n", DateTime.Now.ToShortTimeString());
 
           // Parse out the information that was part of the message.
           foreach (string key in e.Collection.Keys)
           {
               message.AppendFormat("{0}: {1}\n", key, e.Collection[key]);
 
               if (string.Compare(
                   key,
                   "wp:Param",
                   System.Globalization.CultureInfo.InvariantCulture,
                   System.Globalization.CompareOptions.IgnoreCase) == 0)
               {
                   relativeUri = e.Collection[key];
               }
           }
 
           // Display a dialog of all the fields in the toast.
           Dispatcher.BeginInvoke(() => MessageBox.Show(message.ToString()));
       }
       

 

이건 이제 메세지를 받았을때 프로그램에 보여주기 위한 이벤트이다. 메세지를 받았을때 메세지 박스로 띄워준다.

 

 

/// <summary>
 /// MS에서 받아온 url을 서버(WCF Service)에 보낸다.
 /// </summary>
 private void SubscribeToService()
 {
     string appid = "1";
     
     //string baseUri = "http://localhost:19976/Notifications/Register?uri={0}&appId={1}";
     string baseUri = "http://192.168.10.174:6060/Notifications/Register?uri={0}&appId={1}";        
 
     string theUri = String.Format(baseUri, httpChannel.ChannelUri.ToString(),appid);
 
     WebClient client = new WebClient();
     client.DownloadStringCompleted += (s, e) =>
         {
              if (e.Error == null)
              {
                  Dispatcher.BeginInvoke(() => UpdateStatus("Registration Success"));
              }
              else 
              {
                  Dispatcher.BeginInvoke(() => UpdateStatus(e.Error.Message));
              }
 
         };
     
     client.DownloadStringAsync(new Uri(theUri));
 }

 

이렇게 서버에게 URI를 보내 준다. WCF Rest 서비스니 웹처럼 파라미터를 넣어서 전달

 

이렇게 해서 클라이언트 완성


NotificationToastClient.zip

Posted by 동동(이재동)
Windows Phone 72011. 5. 27. 18:21

Surface 프로젝트를 들어가기 하루 이틀전(망고 업데이트가 되기전에) 이미 조금 만들어 놓았던

 

Notification 프로젝트였다. 근데 다행히(?) surface 시연이 끝나고 바로 망고가 나왔다 ㅋㅋ

 

조금밖에 안해 놨었기때문에 크게 수정안해도 됬었다..(어짜피 다시 제작 ㅋㅋ)

 

자 그럼 망고버전에서는 어떻게 Toast Notification을 사용하는지 알아보자 이전버전은 이제 무시하자 미리 포스팅 안하길 잘했다 ㅋㅋ

 

망고 버전 샘플이 있음으로 참고 및 많은 수정을 해서 더 쉽게 만들어 보았다.

 

일단 시작하기위해  3가지를 만들어야 한다.

 

-첫번째 윈폰 클라이언트 프로그램

이건 당연히 만들어야 하는것이다

HttpNotificationChannel을 이용하여 MS으로부터 ChennelUri를 얻어 온다. 이 얻어온 URI을 가지고

클라이언트에게 메세지를 보낸다 클라이언트 고유의 ID라 생각하자.

자 이것을 Notification Server에 보내야 한다.

 

-두번째 WCF Rest Service(그냥 WCF 를 써도 돼지만 난 범용으로 사용 하기 위해서 Rest 사용)

자 이제 아까 만든 클라이언트로부터 URI를 받을것이다.

이것을 저장해 놓자.. 서비스가 절대 멈추지 않을꺼라 생각하면 그냥 저장해도 돼지만

리셋될것을 대비해 DB에 저장해 놓는것이 안전하다.(영구적 서비스라면?)

 

-세번째 메세지를 보내는 관리자를 위한 클라이언트

서버랑 클라이언트가 준비되어 있다면 보낼 메세지를 입력하는 UI를 만들어서 관리자가 메세지를 쓰는

프로그램을 만들어야 한다. 이것역시 서버에 저장된 URI들을 받아서 메세지들을 전달한다.

 

자 이제 두번째 부터는 소스와 같이 윈폰 클라이언트 부터 만들어 보자

Posted by 동동(이재동)
Windows Phone 72011. 5. 3. 10:15

일단 링크로 대신 나중에 포스트

http://chriskoenig.net/2010/08/16/customizing-wp7-push-notification-tiles/

Posted by 동동(이재동)