Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

Pierwsza wersja aplikacji, ciasteczka i refactoring — dobreprogramy na Windows 10

Wcześniejsze dwa wpisy przedstawiały kompletny sposób na zalogowanie się do portalu i zarządzanie powiadomieniami. W momencie tworzenia już UI, pod Universal Windows Platform (UWP), okazało się jednak, że potrzebny jest mały refactoring, wymuszony przez cachowanie ciasteczek, które powoduje w pewnych przypadkach problemy. Dodatkowo zmieniło się założenie co do przechowywania danych użytkownika w apce, a także powstały dwa pierwsze ekrany do próbnej wersji aplikacji.

Cachowanie ciasteczek

Plan na napisanie aplikacji zakładał to, iż przy pierwszym requeście będziemy pobierali ciasteczko, a następnie do logowania i pozostałych działań na powiadomieniach będzie ono przesyłane z każdy zapytaniem. Był to dobry pomysł, ale niestety okazało się, że nadpisanie ciasteczka per request nie jest idealne.

Otóż ciasteczko z ID sesji przy logowaniu jest cachowane odgórnie i przesyłane w kolejnych zapytaniach. Problemem jest wówczas to, iż dodając do zapytania własne ciasteczko z ID sesji, idzie ono razem z poprzednią sesją (dorzucaną automatycznie). Wówczas np. po błędnym zalogowaniu (lub wylogowaniu), nadal mogliśmy pobierać powiadomienia z poprzednio zalogowanego użytkownika.

Rozwiązaniem było zatem czyszczenie globalnego ciasteczka i zapisywanego w kontekście aplikacji. Stwierdziłem jednak, że można to rozszerzyć, wykorzystując powyższy fakt i przy okazji zrobić mały refactoring.

Refactoring

HttpClient

Na początek pozbyłem się klasy WebRequest i użyłem HttpClient (z Windows.Web.Http, nie z System.Net.Http), co było sugerowane w komentarzach. Faktycznie WebRequest w UWP był wrzucony tylko z czystej przyzwoitości i raczej nie powinno się już go używać w tego typu apkach. Główną jednak zaletą jest czystsza implementacja, niż w przypadku WebRequesta.

Brak jawnego pobierania ciasteczka

Wyrzuciłem kod, który tworzył pierwsze zapytanie do strony. Jego jedynym celem było pobrania ciasteczka, które miało być jawnie przechowywane i wysyłane przy każdym następnym requeście. Nie jest to zupełnie już potrzebne. Wystarczy, że usuniemy ciasteczka związane z sesją, wówczas przy poprawnym logowaniu serwer zwróci nam żądane ciasteczko. W ten sposób zaoszczędziliśmy zarówno na szybkości, jak i na ilości przesyłanych danych. Obecnie przed logowaniem czyszczone są ciasteczka: typowe .NETowe ASP.NET_SessionId, a także dodatkowe - NGDP_Auth.

Bez jawnej obsługi cookie

Ostatni element to samo ciasteczko z sesją. Obecnie nie ma potrzeby zarówno przechowywania go jawnie w aplikacji, jak i doklejania do każdego zapytania. Cache w aplikacji sama będzie trzymał ciasteczko, niezbędne do identyfikacji użytkownika. Wbudowany cache na poziomie systemu (per aplikacja), działa nawet po zamknięciu programu, więc odpada tutaj potrzeba przechowywania go jawnie.

Teraz przy uruchamianiu aplikacji, a przed logowaniem, wystarczy sprawdzić, czy istnieje jeszcze nieprzeterminowane ciasteczko z ID sesji w aplikacji.
Dodatkowo, pozwoli to na stworzenie aplikacji, w której nie będzie przetrzymywanego hasła, a także jawnego trzymania ciasteczka do sesji zalogowanego użytkownika. Nie trzeba się martwić zatem o swoje dane :)

Obecnie logowanie wygląda w następujący sposób:

using (var httpClient = new HttpClient()) { request = new HttpRequestMessage(HttpMethod.Post, new Uri(Const.UrlLogin)); request.Content = new HttpFormUrlEncodedContent(new[] { new KeyValuePair<string, string>("what", "login"), new KeyValuePair<string, string>("login", login), new KeyValuePair<string, string>("password", password), new KeyValuePair<string, string>("persistent", "true"), }); try { response = await httpClient.SendRequestAsync(request); } catch (Exception) { return false; } } return response.StatusCode == Windows.Web.Http.HttpStatusCode.Ok;

Samo pobieranie powiadomień to niemalże dwie linijki kodu:

using (var httpClient = new HttpClient()) { request = new HttpRequestMessage( HttpMethod.Get, new Uri(Const.UrlNotifyWithTimeStamp)); response = await httpClient.SendRequestAsync(request); }

Czyszczenie ciasteczek robione jest w następujący sposób:

var httpFilter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter(); httpFilter.CookieManager.DeleteCookie( new HttpCookie(Const.CookieSessionName, Const.UrlDomain, "/")); httpFilter.CookieManager.DeleteCookie( new HttpCookie(Const.NGDP_Auth, Const.UrlDomain, "/"));

Aplikacja - pierwsza wersja

Oczywiście, jak już wszystko zaczęło działać postanowiłem zrobić wstępny projekt, który będzie pozwalał na przetestowanie naocznie nowych elementów.

Do tworzenia aplikacji używam MVVM Light Toolkit. Co ciekawe, dostępne są już nowe XAML Behaviors, które stworzenie zostały m.in. pod UWP (domyślny szablon z MVVM Lighta używa starej wersji, dedykowanej Windows 8.1). Zapewne niedługo dorzucę także Cimbalino Toolkit, który znacznie uprzyjemnia pracę z UWP .

Obecne efekty nie są piękne, ale pozwalają na doszlifowywanie obecnych rozwiązań i tworzenie nowych elementów. Poniżej wrzucam kilka screenów z aplikacji na Windows 10 i Windows 10 Mobile. Zaznaczam, że nie są to mockupy, a screeny z działającej już aplikacji ;)

Windows 10

Windows 10 Mobile

W kolejnym odcinku...

W przyszłych commitach zapewne postaram się doszlifować listę z powiadomieniami. Jednakże to nie ona jest priorytetem. Chciałbym w następnym wpisie przedstawić sposób na działanie aplikacji w tle. Całość będzie sprowadzała się do pobierania co jakiś czas listy z powiadomieniami. Jeśli okaże się, że jest jakieś nowe powiadomienie, wówczas system wyświetli odpowiedni komunikat:

Zatem, do następnego ;)

Aktualne źródła można znaleźć na GitHub pod adresem:https://github.com/djfoxer/dp.notification
 

windows programowanie urządzenia mobilne

Komentarze

0 nowych
tylko_prawda   10 #1 27.03.2016 16:13

A ja dalej czekam na finalną wersję.

mordzio   14 #2 27.03.2016 16:51

Już nie mogę się doczekać finalnej wersji:)

PC MASTER RACE   7 #3 28.03.2016 12:13

Powiadomienia na pulpicie że pojawił się komentarz na blogu bardzo by mi kiedyś uprościło życie. Można byłoby w miarę na czas odpowiadać na pytania oraz ewentualnie kasować spam z komentarzy.

Czy takie powiadomienia będą działały także na telefonie?

djfoxer   17 #4 28.03.2016 12:49

@tylko_prawda: Będzie, deweloping musi trochę potrwać :P Jak na budowie :)

@mordzio: Jeszcze trochę :P

@PC MASTER RACE: W pierwszej kolejności będą na Windows 10 i Windows 10 Mobile. Wersja na Androida i iOS możliwe, że będzie tworzona po zakończeniu prac nad W10 i M :)

pcmasterrace   8 #5 28.03.2016 13:56

@djfoxer: Developer stawiający w pierwszej kolejności na Windows 10 Mobile, zamiast na Androida/iOS. Rzadko spotykane, można wiedzieć, co Cię skłoniło do tej decyzji?

PC MASTER RACE   7 #6 28.03.2016 15:03

@djfoxer: "W pierwszej kolejności będą na Windows 10 i Windows 10 Mobile. Wersja na Androida i iOS możliwe"

Jak będzie działało na W10M to na pewno wypróbuję. Powiadomienia push to lepsze niż otwieranie kilka razy strony by zobaczyć czy ktoś coś skomentował na blogu. Szkoda że nie było takiej funkcji pół roku temu gdy mocno angażowałem się w blogowanie.

Obsługa powiadomień to będzie duży plus dla osób które piszą blogi lub uczestniczą w komentarzach. Czuję że ruch na stronie znacznie wzrośnie gdy każdy uczestnik będzie miał powiadomienia na pulpicie oraz w telefonie. Brakuje jeszcze wątkowania komentarzy w jakieś drzewko i powstałaby idealna grupa dyskusyjna.

Autor edytował komentarz.
mordzio   14 #7 28.03.2016 15:17

@djfoxer: Jak coś, to zgłaszam się na ochotnika do beta testów!

arlid   14 #8 28.03.2016 17:02

Świetny wpis :D Masz talent, nie chcesz trochę tej wiedzy pożyczyć? ;p Tylko trochę designu zrób :)

stasinek   10 #9 28.03.2016 21:34

@djfoxer: The MIT License (MIT) - cool! :>

1. Post logowania: httpRequestMessage(HttpMethod.Post,"https://ssl.dobreprogramy.pl/Providers/LoginProvider.ashx?v=" + Math.Round(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds, 0)); Z parametrami POST: "what"=login, "login"=nick, "password"=hasło, "persistent"= "true";
2. Pobranie listy typów powiadomień w formacie tekstowym JSON: http://www.w3schools.com/json/: HttpRequestMessage(HttpMethod.Get,"http://www.dobreprogramy.pl/Providers/NotifyHelper.ashx?ping=ping&_=" + Math.Round(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds, 0));
3. Zdekodowanie odpowiedzi JSON("Date","Type") i rozdzielenie do elementów UI.
4. Zapisanie zmian dla powiadomień:
HttpRequestMessage(HttpMethod.Post,"http://www.dobreprogramy.pl/Providers/NotifyHelper.ashx"); Z parametrami POST: method+"[]", id;

method to ->
"markAsRead" lub "deleteNotify"
id to ->
case "comment":
case "comment_blog":
case "program_update":
case "contest":
case "friends_accept":
case "friends_invite":
case "blog_annotation":
case "private_msg":
case "mention":
case "license":
case "badges":

A co z awatarem?

Autor edytował komentarz.
djfoxer   17 #10 29.03.2016 00:18

@pcmasterrace: Pracuję w .NET i od początku z WP jestem związany, stąd ten wybór. Android/iOS będzie później, może w Xamarinie.

@PC MASTER RACE: Może warto zatem powrócić do blogowania :)

@mordzio: Zapisane ;)

@arlid: Instaluj VS, pobierz źródła i śmiało patrz jak wygląda kod :) Co do UI, wygląd słabo, ale finalnie będzie ładnie ;)

djfoxer   17 #11 29.03.2016 00:22

@stasinek: Wypisałeś elementy z mego gita, spoko ale... jak mam to skomentować? ;)

"id to -> (...)" ID do zarządzania powiadomieniami to nie jest typ posta :) a ID określające unikalny identyfikator powiadomienia.

"A co z awatarem?" - ?? :D Gdzie tu awatar? ocb? :)

stasinek   10 #12 01.04.2016 20:37

@djfoxer: No własnie, gdzie? Co z avatarami? Jak je przyporządkować do nazwy usera? Inspect Element -> djfoxer avatar -> img src="http://avatars.dpcdn.pl/imgc/Avatar/142792/g_s_70x70_-_-_142792xbanner2.png.166b... style="width: 70px; height: 70px;"

[kontekst]: Masz zdefiniowaną funkcje która koryguje adres http włascie dla avatara.. co wynikałoby z nazwy funkcji. Nie wiem po co ale okej coś jest. Niestety nie znazałem fragmentu który by z niej korzystał. Problem jeszcze nie został rozwiązany lub nie zauważyłem pierwszych przymiarek. Stąd pytanie o av. Nie przeczytałem powyższego wpisu(tylko ogarnąłem wzrokiem). Ponieważ coś już działa zajrzałem do repo gita próbując zrozumieć jak. Używając edytora komentarzy jako ułatwienie w "kompilowaniu" podsumowałem wszystko co jest niezbędne do napisania programu po swojemu we własnym środowisku. Z kodu MIT się cieszę chociaż w sumie kod mi nieprzydatny tylko ściągawka z nazw formularzy, potrzebnych parametrów post, formatu danych powiadomień i znaczenia pól. Gdy przeczytałem Twój wpis zauważyłem odpowiedzi na problem ciasteczek - nadal nie kapuje ale.. mniejsza z nimi, no i skrótowy opis działania(komentarz okazał się zbędny) do pełni szczęscia pozostał Avatar.

Autor edytował komentarz w dniu: 01.04.2016 20:42
djfoxer   17 #13 06.04.2016 13:25

@stasinek: Avataru nie trzeba nigdzie przyporządkowywać. To jest tylko url per notyfikacji (nazwa może być myląca, ale tak już portal to zwraca). Tak naprawdę Avatar jest tylko url do obrazka, który zwraca portal w req. Raz jest to url do avatara usera , raz url do obrazka z logiem np. odznaki. Tylko tyle. Obrazek jest bezpośrednio wyświetlany na widoku. Url do brak usera nie ma prefixu http, wiec go muszę dorzucić.