RSS

Blog

Projektowanie oprogramowania w świecie .NET. Agile, OOP, wzorce projektowe, DDD, ORM, TDD, AOP i inne...

EuroManager. Transfer danych do aplikacji Silverlight

31 sierpnia 2010 Odsłon: 107

W poprzednich artykułach opisałem dość szczegółowo implementację odtwarzacza relacji meczowych, zrealizowanego jako aplikacja Silverlight umieszczona na stronie ASP.NET MVC. Skomplikowaną kwestią okazało się przekazywanie danych wejściowych do tej aplikacji. W większości przypadków w takich sytuacjach potrzebujemy przekazać tylko proste informacje, jak nazwa użytkownika czy ID, po którym - poprzez usługi WCF - możemy dociągnąć resztę danych. Tutaj jednak wolałem unikać opierania się o WCF (potencjalne problemy hostingowe), a zakres danych do przekazania jest dość obszerny.

Byłem więc zmuszony do skorzystania z podstawowego mechanizmu, czyli parametrów kontrolki Silverlight. Normalnie wygląda to tak, że embedując taką kontrolkę na stronie w tagach <param> możemy przekazać pewne wartości, w tym m.in. initParams, do których mamy potem wygodny dostęp z poziomu Silverlight. Poniżej prosty przykład jak mogłoby to wyglądać.

     <div id="silverlightControlHost"> 
         <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="1000px" height="700px"> 
             <param name="source"  value="ClientBin/GameViewer.xap" /> 
             [...]
             <param name="initParams" value="String1=abc,String2=xyz" /> 
             <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration: none"> 
                 <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style: none" /> 
             </a> 
         </object> 
     </div>
 

Tak podane parametry możemy teraz wykorzystać w kodzie aplikacji Silverlight - w moim przypadku zapamiętuję całą kolekcję dla potrzeb dalszego przetwarzania.

         private void Application_Startup(object sender, StartupEventArgs e)
         {
             this.RootVisual = new MainPage();
 
             initParams = e.InitParams;
         }
 

Jak widać, wartość initParams jest napisem o dość sztywnym formacie, w którym nie bardzo można przekazać wprost jakiekolwiek bardziej skomplikowane dane. Jak więc przekazać tam złożony graf obiektów reprezentujących zdarzenia meczowe? Ja posłużyłem się w tym celu serializacją do JSON, wspartą dodatkowo kodowaniem. Poniżej ogólny schemat całej komunikacji.

Przekazywanie rezultatów meczu przez poszczególne warstwy

Przekazywanie rezultatów meczu przez poszczególne warstwy.

Logika symulatora meczów produkuje wynik w postaci grafu obiektów. Jego transformacja na DTO (Data Transfer Objects) w serwisie jest tutaj mało ciekawa - zwykłe mapowanie obiektów, więc to pominiemy. Najważniejsze jest to, co dzieje się w kontrolerze, w metodzie obsługującej żądanie - poniżej jej kluczowy fragment.

         GameData gameData = simulatorService.Play();
 
         using (MemoryStream stream = new MemoryStream())
         {
             var serializer = new DataContractJsonSerializer(typeof(GameData));
             serializer.WriteObject(stream, gameData);
             ViewData["GameData"] = Convert.ToBase64String(stream.ToArray());
         }
 

Obiekty DTO są więc najpierw serializowane do formatu JSON, a wynik tej operacji jest dodatkowo enkodowany przy pomocy metody ToBase64String klasy Convert. Tak przetworzony string może być już bezpiecznie wstawiony do kolekcji initParams, co zostało zrealizowane na stronie aspx w następujący - nie najpiękniejszy, przyznaję - sposób.

         <% Response.Write("<param name=\\"initParams\\" value=\\"" + "GameData=" + ViewData["GameData"] + "\\" />"); %>
 

I to wszystko. Pozostaje jeszcze tylko odtworzenie grafu po stronie aplikacji Silverlight. Realizuje to view model w jednej z metod inicjujących odtwarzanie.

         byte[] data = Convert.FromBase64String(gameData);
 
         using (MemoryStream stream = new MemoryStream(data))
         {
             DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(GameData));
             result = (GameData)serializer.ReadObject(stream);
         }
 

Trzeba tutaj zwrócić uwagę na jeszcze jeden problem. Klasy, do których deserializujemy, muszą mieć taką samą strukturę, co klasy źródłowe (czyli DTO zdefiniowane na poziomie serwisów). Normalnie rozwiązalibyśmy to w taki sposób, że umieścilibyśmy te klasy we współdzielonej assembly, w tym przypadku jednak nie możemy tego zrobić, gdyż projekt Silverlight targetuje inny framework. Można to obejść na parę sposobów, np. linkując te same pliki w dwóch projektach, ale ja zdecydowałem się na razie po prostu zduplikować wszystkie te klasy (pamiętajmy, że to tylko dane - nie ma tam żadnych zachowań, więc nie jest to aż takim problemem).

Dane przekazywane na stronie w takiej zakodowanej postaci mają sporą objętość (w tej chwili jest to ok. 1 MB na pięcominutowy mecz), dlatego rozważam też wprowadzenie kompresji w dalszym etapie. Ponieważ jednak Silverlight nie uwzględnia części .NET Framework z tą funkcjonalnością, trzeba byłoby posiłkować się zewnętrzną biblioteką, dlatego na razie odkładam to na później.

Jak zawsze, pełny kod źródłowy można przeanalizować na stronie projektu na CodePlex:

http://euromanager.codeplex.com

Komentarze

Aktualizacja danych...
Aktualizacja danych...

Kontakt CV

Ja

Rafał Barszczewski
rb07 at interia.pl
gg: 1242248

Sonda

Jakiego O/R mappera używasz najczęściej w .NET?







Aktualizacja danych...

RSS

20 września 2008

Jak widać, spore zmiany. Zaimplementowałem najważniejsze funkcjonalności, które powinien mieć każdy silnik blogów, a których do tej pory u mnie brakowało. Chodzi mi tu przede wszystkim o tagi i RSS. Poza tym strona startowa bloga będzie teraz wyświetlać najnowszego posta, a na panelu bocznym pojawiła się lista ostatnich wpisów.

Ponadto, postanowiłem wznowić pisanie postów (a właściwie je rozpocząć - bo na dobrą sprawę nigdy poważnie nie zacząłem). W końcu w jakimś celu to wszystko zaprogramowałem ;) Tematyka, którą będę chciał w najbliższym czasie poruszyć, obejmuje zagadnienia związane z projektowaniem i testowaniem aplikacji oraz metodykami i narzędziami, które te procesy wspomagają. Zapewne najwięcej będzie o Domain-Driven Design i Test-Driven Development, choć spróbuję podejść do tych tematów bardzo pragmatycznie (technicznie). Mam też plan, żeby w miarę pisania kolejnych części powstawała konkretna, przykładowa aplikacja, która mogłaby posłużyć jako case-study. Co z tego wszystkiego wyjdzie - zobaczymy niebawem.

13 kwietnia 2007

Nie doszedł (na razie) żaden nowy wpis, ale za to przeorganizowałem trochę ten dział. Na głównej podstronie znajdują się teraz same nagłówki wpisów, a całość możemy przeczytać (i skomentować) po przejściu do szczegółów.

21 października 2006

Pierwszy, historyczny wpis w moim blogu. Od tej pory postaram się regularnie dodawać nowe posty. A już niedługo - moje wrażenia z Microsoft Technology Summit (24-25.10).