Programistyczne wywołanie debuggera

Jeśli zdarzyło wam się kiedyś debugować przez Console.WriteLine(…) lub dzielić przez zero, tylko po to aby odpalił się debugger I podpinać do tego visual studio to ta linijka będzie dla was na wagę złota:

System.Diagnosticks.Debugger.Launch();

Gdy wykonywany kod dojdzie do tej linijki pojawi się okienko z pytaniem czy chcesz debugować aplikację, po “jesie” VS dopina się do procesu I normalnie można korzystać z dobrodziejstw inwentarza. Sztuczka przydatna gdy kod jest uruchamiany przez zewnętrzny proces, a wy dostarczacie jedynie bibliotekę z kodem.

Debugger.Launch() uwalnia od wszelkiej maści dzielenia przez zero, pisania na konsole, rzucania wyjątków, robienia MessageBox, żeby zaczekało na dopięcie debuggera, sleepów, etc. Złoto!

ps. Może ktoś nie wie, ale w javascript jest coś takiego jak debugger;

Nauka uczenia się i rozwijania się część 3 – podcasty

Oskar i Kokos zebrali w swoich postach całkiem sporo materiału na temat skąd i jak można czerpać wiedzę i o tym jak się uczyć. Ich wpisy można znaleźć:

Oskar: Nauka uczenia (się)
Kokos: Jak się rozwijać?

Ja dodam od siebie jeszcze jedną rzecz, która nie została wcześniej wymieniona, a moim zdaniem daje sporo. To podcasty. Słuchając ich nie tyle uczę się danej technologii, czy jednego słusznego rozwiązania, a raczej dowiaduje się o innych, alternatywnych do codziennej pracy, rozwiązaniach które może kiedyś da się wykorzystać. Moja lista podcastów:

  • .Net rocks – pierwszy podcast którego słuchałem, skupia się wokół .net
  • A moment of science: Audio – krótkie historyjki ze świata technologi i ogólnej wiedzy
  • Being the worst – mam na liście, ale jeszcze nie dotarło do odtwarzania
  • Coding Blocks – techniczny podcast, skupiający się na .net
  • Full Stack Radio – różnie bywa, czasami wywiady z autorami produktów/bibliotek, czasami opowieści o architekturze i programowaniu. Warto posłuchać tych opowieści, mnie zainspirowały do kolejnego wpisu
  • Hanselminutes – sam Hanselmann, kiedyś technicznie, teraz równouprawnienia, szczerze mówiąc od jakiegoś czasu najczęściej przeskakuje, przykro mi Scott
  • Herding Code – technologicznie, różne osoby, różne technologie
  • JavaScript Jabber – javascript
  • Mała Wielka Firma – podcast o budowaniu własnego przedsiębiorstwa, bardzo fajnie i ciekawie opowiadają
  • Radiolab – opowieści, świetnie przygotowane słuchowiska, czasem moralizujące, czasem opowiadające historię leków, czasem po prostu zabawne, przesłuchałem od początku wszystkie
  • TED Radio Hour – TED w radiu
  • ThoughtWorks – opowieści z firmy, liczę że będą kiedyś ciekawe rzeczy

I ile wcześniej słuchałem każdego epizodu z każdego źródła od deski do deski, to teraz mają ich duży wybór pomijam te, które nie są tak bardzo porywające. Zdarza się także, że jedna osoba występuje w różnych wywiadach dla różnych podcastów, a mówi o tym samym, wtedy również szkoda czasu.

Jeśli chodzi o aplikację do podcastów to szczerze polecam Podcast Addict dla androida. Używam od 2 lat I nie zamierzam zmieniać na nic innego.

Zapis i odczyt data-attribute w DOM

Czasami trzeba zapisać coś w strukturze DOM, a potem odczytać te dane ponownie. I ponownie zapisać i odczytać i jeszcze raz. Z pomocą przychodzi wtedy nieśmiertelne jQuery. Znajdujemy wtedy interesujący nas element $(element) a następnie przy pomocy metody .data(“…”) odczytujemy wartość, lub .data(“…”,”…..”) zapisujemy wartość. jQuery lubi te dane sobie zapisać w swoim cache. Może się więc okazać, że każdy kolejny odczyt wskazywać będzie zawsze tą wartość, którą odczytaliśmy za pierwszym razem. Co wtedy? Są dwa sposoby; kiedyś udało nam się rozwiązać ten problem korzystając z innej metody, ale też jQuery; mianowicie .attr(“data-….”) i symetrycznie .attr(“data-…”, “…”) do odpisu i zaczytu (literówki!). Czasem i to nie wystarcza i wtedy należy sięgnąć po wanilie i skorzystać z getAttribute(“data-…”) oraz setAttribute(“data-…”,”…”) – te ostatnie zawsze działają. Jeden jedyny minusiczek, to taki: że jest to wyłom w spójności kodu, tzn. jeśli wszędzie używamy jQuery, a gdzieś wanilii, to dla części może to kłuć w oczy.

 

//EDIT (05.03.2016)
Przygotowałem przykład dostępny w jsfiddle jak i w giscie. Wygląda na to, w zmęczeniu przegapiłem pewne zależności lub coś działało jeszcze inaczej. Mianowicie problem z odczytem pojawia się wtedy gdy zapiszemy do data przy pomocy setAttribute a odczytamy za pomocą $.data, lub zapiszemy $.attr i odczytamy $.data. W tych przypadkach dane nie zostaną odświeżone. Sami sprawdźcie. Podziękowania dla @jarekkoziol za bycie ciekawskim.

GIST:

JSFiddle:
https://jsfiddle.net/jstadnicki/ydtry0c9/

Zamień bóla na enuma

Dlaczego zamienić? Moim zdaniem czytelniej i jasno sformułowana myśl i łatwiej zrozumieć. Nie chodzi o prosty przypadek, gdzie zamiana polegałaby na zamianie true/false na MyEnum.True/MyEnum.False – nie nie, to byłoby szaleństwem. Ale może od razu do kodu, bo czas nagli dzisiaj.

Pierwszy przypadek, wszystko działa jak należy:

Jakaś tam klasa filtrów, przyjmuje (@3) identyfikator, nazwę i bit, które oznacza że filtr będzie grupą lub nie (w zasadzie nie wiadomo, czym jest nie-grupa)

Teraz wykorzystanie:

Zasadniczo prosty kod, jest jakaś lista filtrów (@5). Następnie dodajemy filtry; pierwsze id, jakaś nazwa i true, potem id, nazwa i false. Osoba nowa w projekcie, lub nowa w tej części kodu na pierwszy rzut oka nie będzie wiedzieć co to oznacza. Następne dwie linijki są trochę bardziej rozgadane, bo jawnie mówią jak interpretować ostatniego bool’a.
Dalej szukamy tylko tych, gdzie IsGroup jest ustawione na true (@12). Jeszcze dalej wołamy metodę, która robi to samo, ale na podstawie parametru wejściowego (@18). Najczęściej gdy się tworzy takie metody nie zwraca się dużej uwagi na nazwę parametru, bo albo to R# wygenerował, a on robi dobrze, albo jest to jedna linijka i nie muszę się nad tym za bardzo skupiać. Rzeczywiście sama metoda jest prosta, trudno się pomylić do czego służy parametr i gdzie go wykorzystać.
Spójrzcie teraz na klienta tej metody, ma przesłać dwa parametry, listę filtrów (to proste), a potem flagę która oznacza group – group co?! Trzeba zajrzeć do ciała metody, żeby sprawdzić co oznacza ten parametr i jak mam go wykorzystać. Można też poprawić nazwę parametru lub (czuję obrzyd jak to piszę) napisać dokumentacja.

A co gdyby napisać kod w taki sposób:

Na scenę wchodzi tajemniczy FilterType:

Jak widać, tajemniczy bohater to enum, które jawnie definiuje jakiego rodzaju może być filtr:

  • 0 – nie został określony, nikt nie wie, nikt nie słyszał. Jeśli w ten sposób został zainicjalizowany, to najprawdopodobniej nie zostanie nigdy wykorzystany
  • 1- Typ grupowy
  • 2- Typ pojedynczy (aha, teraz to trochę jaśniejsze)

Prosty klient klasy Filtr, może wyglądać jakoś tak:

Na początku ponownie tworzymy listę, tym razem nie trzeba zgadywać co oznacza true/false. Nie trzeba także uciekać się do używania nazwanych parametrów aby rozjaśnić intencje.
Następnie gdy wybieramy z kolekcji filtry (@12), znowu w jasny sposób mówimy o typie, który nas interesuje. I wreszcie na koniec metoda filtrująca (@18) także w jawny sposób definiuje parametry których wymaga do działania.

Co jeszcze dobrego płynie z przyjęcia enuma? Jeśli pojawi się nowy rodzaj, nie trzeba będzie wprowadzać kolejnego bool’a który będzie mówić, czy filtr jest czy nie jest danego rodzaju. Domyślnie filtr jest nie znanego typu, więc wszystkie podczas poszukiwać za grupowym/pojedynczym takie znaleziska się nie pojawią. Nawet gdy nazwa parametru będzie do bani, sam tym parametru sprzeda intencje programisty i użytkownik metody (@18) będzie wiedzieć jakiego rodzaju wartość ma przesłać, aby otrzymać interesująco go wynik.

I jeszcze na koniec: oczywiście że ciężko tworzyć enum’y do każdego wykorzystania bool’a. Równie ciężko jest pisać kod który działa i jest czytelny, bezbłędny czy zoptymalizowany – a jednak każdy się stara.

Miłego wieczoru!

Logowanie przy pomocy Facebook, Twitter czy Google – OWIN Katana na ASP MVC 5

Następny wpis, tym razem już na nowym systemie i nowej własnej domenie. Zobaczymy czy będzie tak jak z samochodami, gdzie wizyta na myjni daje dwa konie mechaniczne więcej. Ostatnio pisałem więcej filozoficznie, dzisiaj powrót do twardej rzeczywistości.

Obejrzałem nie dawno na pluralsight fajny i krótki kurs o OWIN i Katana i częścią wiedzy chce się z wami podzielić.
Kto z was zaczynał projekt ASP MVC z włączonymi indywidualnymi kontami użytkowników? Ja na pewno! Także ja, gdy patrzyłem co się dzieje w OWINIE (w części konfiguracyjnej) i AccoutController łapałem się za głowę i zastanawiałem się WTF? Oczywiście próbowałem zrozumieć o co tam chodzi i czemu to wszystko jest tak “fajnie” napisane, niestety nie starczyło mi na to nigdy cierpliwości. Koniec końców pogodziłem się z tym faktem i korzystałem z tego tak jak jest, działało a ja nie zadawałem pytań – sprzedawać!

Teraz to wszystko może się zmienić! (dramatyczna muzyka i suspens – teraz!)

Aby to wszystko zrozumieć, zacząć należałoby od stworzenia pustego projektu MVC5 (tak, wiem staroć) – żadnych dodatkowych referencji, nic! Jak się bawić to na trylion procent. Na koniec wpisu, znajdziecie link do całego projektu. Dodajemy samodzielnie referencje do OWINowych rzeczy, tak aby moje i wasze referencje w tej kwestii się zgadzały:

  • Microsoft.Owin
  • Microsoft.Owin.Host.SystemWeb
  • Microsoft.Owin.Security
  • Microsoft.Owin.Security.Cookies
  • Microsoft.Owin.Security.Facebook
  • Microsoft.Owin.Security.Google
  • Microsoft.Owin.Security.Twitter

Z racji tego że projekt będzie oparty o MVC, nie można zapomnieć o:

  • System.Web.Mvc
Kompletna lista referencji w projekcie
Kompletna lista referencji w projekcie

Gdy to mamy ogarnięte, warto dodać plik z punktem wejścia do aplikacji, wykorzystany zostanie także do konfiguracji facebooka, twittera czy G+ oraz ogólnej authentykacji, u mnie wygląda on tak:

Co tam ciekawego? Na początku (@14) informujemy aplikację, o chęci korzystania z autentykacji opartej o ciastka. Ciastko przenosząca tajne dane nazywamy ThisCanBeAnythingYouLike. Następnie (@20-@41) wpinamy kolejne warstwy umożliwiające użytkownikom logowanie się przy pomocy FB, Twittera czy G+. Należy podać sekretne kody jednoznacznie identyfikujące waszą aplikacje.

Uwaga (@32) tutaj null oznacza, że nie interesuje mnie walidacja certyfikatów Twittera, oznacza to nie mniej, nie więcej, że jeśli ktoś podszyje się do Twittera i sprzeda mi swój certyfikat, ja to łyknę jak młody pelikan. Taka zagrywka przejdzie na blogu. Na żywej produkcji, należy odnaleźć aktualnie używane certyfikaty Twittera i dodać jest do walidacji. Dodatkowo zwracam uwagę, że wszystkie formy authentykacji korzystają z tego samego ciastka, znowu na blogu nie robi mi to różnicy skąd i jak i czym logują się moi użytkownicy. Produkcja rządzić może się swoimi prawami.
“/Auth/Login” (@14) ta linijka mówi, gdzie należy się przekierować gdy użytkownik nie będzie zalogowany, a aplikacje będzie tego wymagać.
Dla przypomnienia odpowiednio atrybuty AllowAnonymousAttribute oraz AuthorizeAttribute.

Skoro już powiedziałem o przekierowaniu do “/Auth/Login” (Auth controller, Login action) zajrzyjmy co kryje się w tej klasie:

Wielkiej ilości kodu nie ma (gdzie jest AccountController?!). Zaczynając od metody [HttpGet]Login (@15) tworzymy prosty pusty model do logowania się użytkownika. Z OWINa wyciągamy informacje o zarejestrowanych providerach (dostarczycielach?) logowania i wpychamy do modułu, który potem renderujemy.

W parach pracuje się lepiej, dlatego istnieje także [HttpPost]Login (@29) który przyjmuje ten sam model(pamiętamy, że to tylko wpis na blogu i nie maiłczymy że model!=dto!=viewmodel). W klasie są informacje o nazwie i haśle, następuje skomplikowana weryfikacja i jeśli dane są poprawne tworzymy w locie użytkownika. Nadajemy mu także pewne cechy: nazwę oraz identyfikator. Tak zdefiniowanego użytkownika logujemy przy wykorzystaniu OWINa. I wracamy do domu, jeśli weryfikacja się nie powiedzie, dajemy kolejną szansę.

Dla znudzonych oferujemy opcję wylogowania (@47) jak zawsze wszystko kręci się wokół OWINa.

Wreszcie! WRESZCIE! Jak zobaczycie zaraz na przykładzie z razora, tutaj obsługujemy kliknięcie użytkownika, gdy wybierze ono (!on i !ona) opcję logowania się przy pomocy FB, Twitter czy G+. Jako parametr wejściowy przyjdzie nazwa providera. Następnie na OWINie i autentykacji wywołujemy metodę Challange z parametrem informującym, że chcemy wrócić do “/secret”. Kod tego kontrolera pokaże na końcu. Po wywołaniu zwracamy jeszcze odpowiedni kod HTTP aby wszystkim formalnościom stało się zadość. Status Unauthorized jest bardzo ważny i nie może zostać pominięty.

No dobrze, skoro tutaj tak mało kodu, to pewnie razor będzie przekombinowany, pomyślało teraz ono. Aby nie trzymać w niepewności:

Pierwsze linie wynikają z braku pełnej integracji z MVC, odpowiednich wpisów w web.config etc. Ignoruj. Linie (@15-@30) to forma gdzie można się zalogować jako aplikacyjny użytkownik. Linie (@32-@37) to pętla, która wyciąga z modelu (ono przypomina sobie teraz AuthController::Login) listę providerów, na jej podstawie tworzy proste linki z nazwą providera oraz odpowiednim id (“Facebook”, “Twitter”, “Google”), które zostanie przekazane do metody SocialLogin (AuthController::SocialLogin) i użyte to rozróżnienia providera.

Co teraz? Gdzie jest reszta, gdzie jest ACCOUNTCONTROLLER? Nie ma i nie potrzeba. Póki co, nie będę nigdzie zapisywać użytkowników. Demo pokazuje tylko jak zalogować się przy pomocy providerów wymienionych powyżej.

Co znaczy zalogowanie? Otóż mniej więcej tyle:

Będziemy w stanie przejść do metody Index, która jest klasie wymagającej autoryzacji. Czyli User.Identity.IsAuthenticated zwróci TRUE. To całkiem fajnie. Oprócz tego, mamy kilka dodatkowych informacji:
Oraz widok:

W widoku widać że interesują nas cechy nadane nam przez system. Nie ważne czy to FB, Twitter, G+ czy my sami (AuthController, Login w wersji POST). Po uruchomieniu aplikacji wynik operacji wyglądają tak:

Wersja lokalna (user:jaroslaw/pass:stadnicki):

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier : jaroslaw
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name : jaroslaw

Wersja z G+

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier : 1#6#9#9#9#2#4#7#1#2#6 (odrobina prywatności)
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname : Jarosław
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname : Stadnicki
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name : Jarosław Stadnicki
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress : jaroslaw.stadnicki@gmail.com
urn:google:profile : https://plus.google.com/+JarosławStadnicki

Itp, itd. Warto zwrócić uwagę, że z G+ (inne też), dostajemy już identyfikator użytkownika, który możemy powiązać ze swoim lokalnie tworzonym kontem. I gdy ponownie przyjdzie gościu z G+ i się zaloguje się i dostaniemy jego ID, będziemy wiedzieć, że on to on, a nie ktoś inny.

Na koniec jeszcze ważna sprawa, oczywiście należy pamiętać aby samodzielnie stworzyć swoje aplikacje odpowiednio na stronach:
https://developers.facebook.com/
https://apps.twitter.com/
https://console.developers.google.com/home/dashboard

Należy także ustawić poprawnie callbacki w tych systemach, u mnie wartość które działały poprawnie to: http://www.xoxox.com

Ej, ale co to za dziwny adres? No tak tak, bo Twitter nie lubi localhost (FB i G+ sobie z tym radzą). Dlatego dla Twittera robi się wyjątek i należy zaatakować windows\sytem32\drivers\etc\host dopisać taką linijkę:

127.0.0.1         www.xoxox.com

Od tej pory www.xoxox.com będzie wskazywać na wasz komputer. Ale jeszcze! Należy na normalnym IIS dodać stronę i pokazać jej, że binarki leżą u was w źródłach. Dodać binding w IIS. I na końcu w Visual Studio przełączyć się z IIS express na normalnego i też korzystać z www.xoxox.com. Można też zignorować twittera i dla testów sprawdzić tylko FB i G+ i korzystać z IIS express na 127.0.0.1

Tyle, od tej pory ja i wy (jaka jest liczna mnoga od ono?) będziemy mogli w prosty sposób logować się społecznościami. Aplikacja dostępna jest pod linkiem:
https://bitbucket.org/jstadnicki/simplesociallogin

Kod do aplikacji zostały zmienione przed publikacją, także aby zadziałały należy wygenerować własne oraz podmienić. Projekt działa pod kontrolą pełnego IIS, to także należy/można zmienić.

To tyle. Życzę miłej zabawy.