-
Postów
1 369 -
Dołączył
-
Ostatnio
Nigdy -
Days Won
2
Typ zawartości
Profile
Fora
Kalendarz
Articles
Pliki
Wszystko napisane przez DevStart Blogi
- Poprzednia
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- Dalej
-
Strona 2 z 9
-
Pamiętam jak mój promotor narzekał, że współczesne oprogramowanie ciągle ma jakieś aktualizacje. „Nikt nie robi solidnych produktów. Ciągle muszą coś naprawiać i aktualizować, zamiast zrobić porządnie. Hurr durr.” Z czasem nauczyłem się, że nie zawsze warto dyskutować z jakąś osobą. Należy zdecydować, czy osoba która coś mówi jest w naszych oczach wartościowa […] Wyświetl pełny artykuł
-
IIS w Windows 10 wspiera już od jakiegoś czasu nową wersję protokołu. W zasadzie prawdopodobnie nic nie musimy robić, jeśli posiadamy prawidłową wersję IIS. Oczywiście użytkownicy muszą posiadać również odpowiednią wersję przeglądarki internetowej. Ich kompatybilność można sprawdzić tutaj. Jak widać, Edge, Chrome, Firefox, Opera czy iOS Safari radzą sobie najlepiej. W przypadku IE, najnowsza wersja wspiera HTTP 2.0 tylko częściowo. Jeśli jeszcze nie zainstalowaliśmy IIS na Windows 10, wtedy przejdźmy najpierw do “Turn Windows features on or off”, a następnie zaznaczamy Internet Information Service: Aktualnie IIS wspiera wyłącznie HTTPS (TLS). Oznacza to, że jeśli chcemy użyć nieszyfrowanego połączenia to HTTP 1.1 będzie wciąż używany. Dodajmy więc kolejny binding HTTPS: I to wszystko co musimy zrobić… Jak widać, nic specjalnego nie należy konfigurować. Wystarczy odpowiednia wersja IIS oraz przeglądarki po stronie klienta. Odpalmy zatem stronę zarówno z HTTP, jak i HTTPS. Spodziewamy się, że nieszyfrowane połączenie wciąż będzie HTTP 1.1: W przypadku HTTPS,HTTP 2.0 będzie użyty: Skrót H2 oznacza oczywiście HTTP 2.0 W przyszłym poście opiszę kolejny element HTTP 2.0, w tym przypadku Server Push, który wymaga pewnych modyfikacji w aplikacji ASP.NET. W celu przetestowania tej aplikacji, potrzebny będzie zarówno serwer IIS wspierający HTTP 2.0, jak i odpowiednia przeglądarka (np. Chrome). Wyświetl pełny artykuł
-
HTTP 2.0 jak wiemy z poprzedniego już wpisu jest protokołem binarnym. Wiemy również, że fundamentalne zasady działania HTTP nie zostały zmienione. Oznacza to, że HTTP pozostaje protokołem bezstanowym. To z kolei w praktyce oznacza, że każde zapytanie musi dostarczać wszelkie informacje potrzebne do odtworzenia stanu aplikacji. Powoduje to, że zarówno ciało zapytania jak i nagłówek po jakimś czasie mogą zawierać dużo informacji, które należy przesyłać w każdym zapytaniu. Kompresja danych, dostarczona w HTTP 2.0 jest kolejnym usprawnieniem poprawiającym wydajność, a w szczególności opóźnienie. HTTP 2.0 dostarcza również kompresje nagłówków, co kompletnie nie było dostępne w HTTP 1.1 (była możliwość jedynie kompresji ciała). Kompresja HTTP 2.0 jest również odporna na atak CRIME (Compression Ratio Info-leak Made Easy), na który był podatny nawet klasyczny HTTPS czy poprzednik HTTP 2.0, a mianowicie SPDY. Jak to możliwe, że HTTPS, który jest szyfrowany może cierpieć na niebezpieczny atak ze względu na dodaną kompresję danych? Jak sama nazwa wskazuje, atak polega na monitorowaniu rozmiaru skompresowanej treści. Prawdopodobnie dodając trochę treści, rozmiar musi się zmienić. Pomimo, że całość jest szyfrowana, to naturalnie rozmiar pakietu jest całkowicie jawny – to informacja, którą atakujący może wykorzystać. W jaki sposób zatem przedstawiony atak może wyglądać? Załóżmy, że chcemy odgadnąć szyfrowany identyfikator sesji. Gdzieś w ciele zapytania musi być przechowywana wartość np. “sessionId=252”. Jednym z fragmentów, które możemy kontrolować jest typ i adres zasobu dla zapytań. Jeśli chcemy wysłać GET do strony głównej wtedy zapytanie będzie wyglądać następująco: GET /home Wyobraźmy sobie, że wysyłamy jednak najpierw poniższy pakiet GET /sessionId=9 Oczywiście cały czas monitorujemy rozmiar pakietu. Następnie kolejny pakiet to: GET /sessionId=2 Co możemy dowiedzieć się z rozmiarów wysłanych pakietów? Czy będą miały identyczny rozmiar? Jeśli kompresja jest użyta, drugi pakiet (sessionId=2) będzie mniejszy niż pierwszy, ponieważ sessionId=2 występuje już w ciele zapytania, które zawiera sekretny identyfikator sesji. Algorytmy kompresji, w dużym skrócie polegają na zastępowaniu duplikatów pewnymi wskaźnikami – np. skrótami. Naturalne zatem, że po kompresji ciąg znaków “AABB” będzie miał mniejszy rozmiar niż “ABCD”. Metodą prób i błędów modyfikujemy zatem pakiet (w tym przypadku adres zasobu), aby rozmiar całości redukował się. Jeśli dodanie kolejne cyfry sesji zwiększa rozmiar, to znaczy, że takowa cyfra nie występuje w zaszyfrowanym ciele i stąd kompresja nie przynosi skutków. Jeśli rozmiar jest mniejszy, pewne fragmenty pakietu się powtarzają i oznacza to dla nas, że odgadliśmy kolejną cyfrę. Widzimy, że przechwycenie zaszyfrowanego pakietu, zawierającego numer sesji może być niebezpieczne dla użytkownika. Pomimo, że nie mamy szans rozszyfrować pakietu, to bazując na rozmiarze możemy spróbować odtworzyć analogiczny pakiet. Podsumowując, do przeprowadzenia CRIME musimy: posiadać próbkę pakietu, zawierającego sekretne dane (np. identyfikator sesji). kompresja danych musi być włączona należy wstrzyknąć pewną treść, np. za pomocą adresu zasobu. W przypadku HTTP 1.1, polecane jest aby wyłączyć kompresje danych zarówno po stronie klienta (przeglądarka internetowa) jak i serwera. HTTP 2.0 nie jest podatny na ten typ ataku. Wyświetl pełny artykuł
-
Zanim przejdę do kolejnych usprawnień w HTTP 2.0, warto poświęcić chwilę na zastanowienie się jak omijamy problemy HTTP 1.1 dzisiaj. Większość stron wciąż opiera się na HTTP 1.1 i nie najgorzej radzą sobie z wydajnością. Oczywiście sporo jest do poprawy, ale strony działają na urządzeniach mobilnych bez ogromnych opóźnień. Mimo wszystko, opóźnienie (latency) jest jednym z podstawowych problemów rozwiązanych przez HTTP 2.0. Zastanówmy się, jak dzisiaj podchodzimy do tego, aby zminimalizować ten problem. Wiemy, że każda strona posiada liczne skrypty JavaScript, arkusze CSS czy pliki graficzne. Każdy zasób jest ładowany pojedynczo. Jeśli zatem mamy jeden plik html, 2 CSS, 5 skryptów JavaScript oraz 10 plików graficznych, razem zostanie wykonanych 18 zapytań do serwera. Jak wiemy z poprzedniego postu, HTTP 1.1 może wspierać co najwyżej HTTP pipelining. Wysyłanie pojedynczych zapytań jest skrajnie wolne na połączeniach satelitarnych czy mobilnych. Nawet jeśli dostawca obiecuje szybki transfer, to wysłanie pojedynczego zapytania i tak będzie wolne. W tym przypadku średni transfer nie ma znaczenia ponieważ zapytania jak i zawartość strony zwykle nie zawierają dużo danych. Jednym z obejść zbyt dużej liczby plików graficznych jest połączenie ich w jeden wielki plik (spriting). Technika szczególnie popularna w dawnych czasach do tworzenia animacji komputerowych – jeden plik prezentował różne klatki animacji. Następnie w zależności, którą klatkę się chciało wyświetlić, wydzielało się konkretny fragment większego pliku graficznego. Podobną technikę można wykorzystać w web – załadować jeden obrazek (pojedyncze zapytanie), a potem wyświetlać konkretne fragmenty w zależności od potrzeb. Oczywiście rozwiązanie bardzo niewygodne ponieważ należy logicznie scalać obrazki co zwykle jest czasochłonne i trudne. Kolejna obejście to definiowanie grafiki bezpośrednio w arkuszach CSS. Zamiast odnosić się do zewnętrznych plików graficznych (które wymagają osobnych zapytań), można osadzać dane bezpośrednio w CSS (embedded images). Programiści ASP.NET z pewnością kojarzą ASP.NET Bundles. Z punktu widzenia jakości kodu, warto rozdzielać kod JavaScript na konkretne moduły. Ma to jednak ogromny wpływ na wydajność – im więcej plików JS tym wolniej załaduje się strona ponieważ należy więcej wysłać zapytań. Rozwiązanie problemu jest proste -scalać wszystkie pliki w jeden wielki skrypt. Wtedy wystarczy, że przeglądarka wyśle jedno zapytanie i wszystko zostanie załadowane. Kolejną analogiczną techniką jest minifikacja (minification). Polega na usunięciu niepotrzebnych znaków takich jak np. komentarze, spacje, znaki nowej linii itp. z pliku JavaScript. Nie są one niezbędne do wykonania kodu, a zajmują miejsce. Dzięki ASP.NET Bundles zostanie to zrealizowane podczas wdrażania aplikacji. Kod zatem pozostanie przejrzyście rozdzielony na różne pliki, a po wdrożeniu, serwer będzie serwował pojedynczy plik. Kolejną techniką jest jest tzw. sharding. Polega na umieszczaniu tych samych zasobów (np. plików graficznych) na różnych serwerach. Jak wiemy, HTTP 1.1 posiada wyłącznie HTTP pipelining, który w wielu przeglądarkach jest i tak wyłączony ze względu na HOL blocking. Przeglądarki starają się zatem zainicjalizować wiele połączeń TCP, które stanowią wtedy niezależne kanały komunikacji. Problem w tym, że specyfikacja HTTP mówiła, że klient może nawiązać maksymalnie dwa równoległe połączenia. Dzięki sharding, mamy te same zasoby dostępne z różnych maszyn. Wtedy okazuje się, że dla każdego serwera możemy nawiązać dwa różne połączenia. Z tego co wyczytałem, dzisiaj można nawiązać więcej równoległych połączeń, ale i tak ze względu na limity korzysta się z sharding. Niestety wszystkie powyższe techniki mają wady. Oprócz oczywistej, która jest zbyt duża złożoność, wcześniej czy później pojawią się problemy z buforowaniem. Scalanie plików w JS spowoduje, że zmiana w jakimkolwiek pliku wymusi przeładowanie całego skryptu. Podobnie z spriting – modyfikacja jednego obrazka wymaga odświeżenia cache w przeglądarce dla całego sprite’a. Wyświetl pełny artykuł
-
Taki krótki news: na stronę serwisu książki wrzuciłem pierwszą część erraty, a na GitHub kody źródłowe, które trafiły do książki. Oprócz tego, również na GitHubie, założyłem repozytorium na rozwiązania ćwiczeń z książki, jeśli ktoś tako chce podesłać - pull requesty mile widziane (pierwsze trzy rozwiązania już są opublikowane). A teraz dłużej, po kolei. Kwestia erraty Od dzisiaj błędy można zgłaszać bezpośrednio na serwisie książki (trzeba założyć konto) - click. Można tam również znaleźć już wrzucone w system błędy, oraz zasady pocztówkowego bug bounty. Póki co "do systemu" wrzuciłem erratę na postawie zgłoszeń, które otrzymałem od premiery do około połowy listopada - większość zgłoszeń otrzymałem w tym okresie, via Facebook, komentarze na blogu, e-mail, IRC, gołębia pocztowego, itp. Postaram się w ciągu kilku kolejnych dni wrzucić pozostałe zgłoszone błędy. Jednocześnie, jeśli ktoś jest wymieniony w podziękowaniach na stronie erraty i jest przy jego zgłoszeniu zaznaczone Erratum-Bronze, Erratum-Silver lub Erratum-Gold, a jeszcze nie otrzymał ode mnie mejla, to prosiłbym o kontakt. Dodam, że pamiątkowe pocztówki będę wysyłał pewnie w połowie lutego - jeszcze nie są wydrukowane (zaległości, zaległości...). Kwestia kodu źródłowego Link jeszcze raz: GitHub /gynvael/zrozumiec-programowanie Do repozytorium trafiły kody znalezione na dysku. Niektóre z nich nie mają przetłumaczonych komentarzy, co będę musiał niedługo nadrobić. Kwestia rozwiązań ćwiczeń Link: GitHub /gynvael/zrozumiec-programowanie-cwiczenia Po kliknięciu na link można poczytać jak zgłosić rozwiązanie. Btw, pierwsze trzy zgłosił Adam Bac (abac00s) - dzięki! Książki papierowe Trochę egzemplarzy jeszcze można kupić w różnych księgarniach (księgarniach internetowych), ale na stronie wydawnictwa już chyba nie (albo zostało kilka ostatnich sztuk). W związku z czym wydawca zdecydował o zrobieniu trzeciego dodruku pod koniec stycznia - tak więc póki co o dostępność nie trzeba się martwić :) Co pozostało do zrobienia Jeszcze sporo. M.in. muszę wrzucić resztę erraty, dokończyć/napisać i opublikować dodatkowe rozdziały, dopisać na stronie serwisu książki jeszcze kilka rzeczy, etc. Ah, i powoli zacząłem nadrabiać zaległą korespondencje z listopada/grudnia - więc jeśli wysłaliście do mnie mejla w tym okresie (który był dla mnie dość "szalony"), i nie dostaliście odpowiedzi, to powinniście ją otrzymać w ciągu kilku dni. Za opóźnienia standardowo przepraszam. I tyle póki co ;) Wyświetl pełny artykuł
-
Kilka postów chcę przeznaczyć na temat HTTP 2.0. Zamiast pisać tylko o nowościach w nowej wersji protokołu, warto najpierw zrozumieć jak działała dotychczasowa wersja czyli HTTP 1.1. Pierwszym problemem HTTP 1.0 oraz HTTP 1.1 była obsługa wielkiej ilości zapytań. Każda strona, aby prawidłowo wyświetlić się potrzebuje załadować mnóstwo zewnętrznych zasobów takich jak skrypty JS, arkusze css czy grafika. Ponadto HTTP oparty jest na TCP więc ponadto mamy do czynienia z TCP handshake zanim połączenie jest zainicjalizowane. Połączenia internetowe są coraz lepsze, ale szybkość załadowania stron nie zawsze jest satysfakcjonująca. Wyobraźmy sobie ekstremalną sytuację. Strona posiada 10 skryptów JS, 2 arkusze CS oraz 10 plików graficznych. Zasoby w HTTP nie są przesyłane razem. Najpierw ściągany jest plik HTML, a potem każdy zasób zewnętrzny jest ściągany jeden po drugim. Po mimo szybkiej, średniej szybkości łącza internetowego, opóźnienie (latency) wiążące się z wysoká liczbą zapytań sprawia, że strona działa wolno. W HTTP 1.0 wszystkie zapytania musiałby być wysyłane pojedynczo (szeregowo). Jeśli mamy zatem 20 zapytań, najpierw musieliśmy wysłać pierwsze, czekać na odpowiedź i dopiero potem wysłać drugie. W przypadku internetu satelitarnego czy mobilnego, strony po prostu wczytywały się bardzo wolno, mimo wysokiej średniej szybkości transmisji. W odpowiedzi na oczywisty problem, w HTTP 1.1 wprowadzono HTTP pipelining. Dzięki temu, możliwe było wysyłanie kilku zapytań w tym samym połączeniu TCP. Korzyści były ogromne. Po pierwsze tylko jeden TCP Handshake. Zamiast czekać na odpowiedź mogliśmy wysłać najpierw wszystkie zapytania, a potem odbierać odpowiedzi jedno po drugim. Niestety musiało to odbywać się na zasadzie FIFO – odpowiedzi musiały przychodzić w tej samej kolejności co wysłane zapytania. Stanowiło to tak ogromne ograniczenie, że większość przeglądarek nie korzysta dziś nawet z HTTP pipelining. Podstawowy problem to Head Of Line Blocking. Wiemy, że odpowiedzi muszą przychodzić w tej samej kolejności co zapytania. Co jeśli drugie zapytanie trwa bardzo długo? Skutek będzie taki, że będzie to blokowało kolejne odpowiedzi i przyszłe zapytania. Jeśli zatem wszystkie zapytania byłyby wysyłane za pomocą HTTP Pipeline efekt mógłby być odwrotny do zamierzonego – jeśli pierwszy element zajmuję bardzo długo, wtedy kolejne muszą czekać. Co jeśli ten pierwszy element tak naprawdę nie jest niezbędny do wyświetlenia większości zawartości na stronie? HTTP pipelining zniwelował problemy związane z opóźnieniem, ale ryzyko blokady HOB odstraszało wielu twórców przeglądarek od adaptacji tego. I tutaj przychodzimy do HTTP 2.0 Multiplexing. Protokół HTTP 2.0 jest binarny, w przeciwieństwie do wersji poprzednich. Wysyłane pakiety stanowią ramki składające się z nagłówku i ciała. Wprowadzono definicje strumieni oraz priorytetów. Dane wysyłane w obrębie dwóch różnych strumieni są niezależne od siebie, a co za tym idzie, mogą się wzajemnie przeplatać. Innymi słowy, HTTP 2.0 multiplexing to prawidłowa implementacja wysyłania wielu zapaytań w obrębie tego samego połączenia TCP. Odpowiedzi już nie muszą być wysyłane w tej samej kolejności przez serwer i zostanie to prawidłowo obsłużone. Wspomniana kolejka FIFO nie jest już potrzebna. Ustawienia priorytetów umożliwia uzyskanie odpowiedzi w dowolnej kolejności. Serwer po utrzymaniu wielu zapytań naraz może skorzystać z priorytetów, aby przetwarzać je w odpowiedniej kolejności. HTTP Multiplexing stanowi jedno z podstawowych usprawnień HTTP 2.0, który wpływa bardzo korzystnie na wydajność stron internetowych, szczególnie w środowisku z wysokim opóźnieniem ( połączenie mobilne). W przyszłych wpisach zajmiemy się kolejnymi usprawnieniami. Dobrą wiadomością jest, że jako programiści nie musimy wiele robić. HTTP 2.0 został zaprojektowany tak, aby mógł zostać wprowadzony bez konieczności aktualizacji istniejącego kodu. Wszystkie pryncypalne zasady takie jak wysyłanie ciasteczek, nagłówki, sesje itp mają nadal rację bytu – HTTP 2.0 to nie zmiana architektury. Wyświetl pełny artykuł
-
W poprzednim wpisie pokazałem, w jaki sposób możemy zaprojektować obsługę błędów. Jak widać mamy do dyspozycji sporo opcji. Z punktu widzenia AKKA.NET nie jest to jednak tak skomplikowane. Wystarczy przeładować jedną metodę i zwrócić odpowiedni obiekt. Tak jak w poprzednim wpisie będziemy testować kod na następującym “systemie”: Dla przypomnienia nasz ApplicationUserActor wygląda następująco: public class ApplicationUserActor : UntypedActor { private readonly string _userName; public ApplicationUserActor(string userName) { _userName = userName; } protected override void OnReceive(object message) { Console.WriteLine("Received by {0}: {1}", _userName, message); } protected override void PreStart() { Console.WriteLine("{0}: PreStart",_userName); base.PreStart(); } protected override void PostStop() { Console.WriteLine("{0}: PostStop", _userName); base.PostStop(); } protected override void PreRestart(Exception reason, object message) { Console.WriteLine("{0}: PreRestart", _userName); base.PreRestart(reason, message); } protected override void PostRestart(Exception reason) { Console.WriteLine("{0}: PostRestart", _userName); base.PostRestart(reason); } } Póki co niewiele mamy tam kodu – głównie hooking, które pomogą nam w zrozumieniu propagacji błędów. Zmodyfikujmy metodę OnReceived tak, aby zasymulować wyjątek: protected override void OnReceive(object message) { if (message.ToString() == "error") throw new ArgumentException(); Console.WriteLine("Received by {0}: {1}", _userName, message); } W celu zdefiniowania obsługi błędów wystarczy przeciążyć metodę SupervisorStrategy aktora zarządzającego. Jeśli chcemy więc obsłużyć wyjątek w ApplicationUserActor, wtedy węzeł zarządzający (rodzic) to ApplicationUserControllerActor. Kod: protected override SupervisorStrategy SupervisorStrategy() { return new OneForOneStrategy((exception) => { if (exception is ArgumentException) return Directive.Restart; return Directive.Escalate; }); } W przykładzie wybraliśmy strategię OneForOneStrategy, którą opisałem już w poprzednim wpisie. W skrócie, rodzeństwo węzła, który spowodował wyjątek, nie będzie odgrywało tutaj żadnej roli. Wystarczy, że przekażemy wyrażenie lambda, które określa co należy zrobić w zależności od typu wyjątku. W powyższym przykładzie restartujemy aktora. Tak jak napisałem w poprzednim poście, mamy cztery sposoby reakcji: public enum Directive { Resume, Restart, Escalate, Stop, } W celu zaprezentowania efektu, stwórzmy dwóch aktorów i wyślijmy serię wiadomości: var system = ActorSystem.Create("FooHierarchySystem"); IActorRef userControllerActor = system.ActorOf<ApplicationUserControllerActor>("ApplicationUserControllerActor"); userControllerActor.Tell(new AddUser("Piotr")); userControllerActor.Tell(new AddUser("Pawel")); var actor1 = system.ActorSelection("/user/ApplicationUserControllerActor/Piotr"); var actor2 = system.ActorSelection("/user/ApplicationUserControllerActor/Pawel"); Console.ReadLine(); actor1.Tell("Sample message I"); Console.ReadLine(); actor1.Tell("error"); Console.ReadLine(); actor1.Tell("Sample message II"); Console.ReadLine(); Widzimy, że w momencie wystąpienia błędu, aktor został zrestartowany. Ze screenu również można zauważyć, że kolejne wiadomości zostaną przetworzone. Stan wewnętrzny został zrestartowany, ale nie kolejka wiadomości. W celu zademonstrowania, że stan wewnętrzny faktycznie jest wymazywany (ponieważ tworzona jest nowa instancja), dodajmy prywatne pole do klasy: public class ApplicationUserActor : UntypedActor { private readonly string _userName; private string _internalState; ... } InternalState jest wyświetlany i ustawiany w OnReceive: protected override void OnReceive(object message) { Console.WriteLine("{0}:Internal State: {1}",_userName,_internalState); if (message.ToString() == "error") throw new ArgumentException(); _internalState = message.ToString(); Console.WriteLine("Received by {0}: {1}", _userName, message); } Teraz widzimy, że po wystąpieniu wyjątku, InternalState będzie pusty: Analogicznie, spróbujmy zmienić dyrektywę restart na resume: protected override SupervisorStrategy SupervisorStrategy() { return new OneForOneStrategy((exception) => { if (exception is ArgumentException) return Directive.Resume; return Directive.Escalate; }); } Po uruchomieniu programu, przekonamy się, że stan wewnętrzny nie jest usuwany: Zmieńmy również strategię na AllForOneStrategy: protected override SupervisorStrategy SupervisorStrategy() { return new AllForOneStrategy((exception) => { if (exception is ArgumentException) return Directive.Restart; return Directive.Escalate; }); } Efekt będzie taki, że wszystkie węzły podrzędne zostaną zrestartowane: Jeśli w jakimś aktorze nie zdefiniujemy strategii obsługi błędów, wtedy domyślna będzie użyta: protected virtual SupervisorStrategy SupervisorStrategy() { return SupervisorStrategy.DefaultStrategy; } Domyślna strategia to z kolei OneForOneStrategy. Warto również przyjrzeć się innym przeciążeniom konstruktora, np.: /// <summary> /// Applies the fault handling `Directive` (Resume, Restart, Stop) specified in the `Decider` /// to all children when one fails, as opposed to <see cref="T:Akka.Actor.OneForOneStrategy"/> that applies /// it only to the child actor that failed. /// /// </summary> /// <param name="maxNrOfRetries">the number of times a child actor is allowed to be restarted, negative value means no limit, /// if the limit is exceeded the child actor is stopped. /// </param><param name="withinTimeRange">duration of the time window for maxNrOfRetries, Duration.Inf means no window.</param><param name="localOnlyDecider">mapping from Exception to <see cref="T:Akka.Actor.Directive"/></param> public OneForOneStrategy(int? maxNrOfRetries, TimeSpan? withinTimeRange, Func<Exception, Directive> localOnlyDecider) : this(maxNrOfRetries.GetValueOrDefault(-1), (int) withinTimeRange.GetValueOrDefault(Timeout.InfiniteTimeSpan).TotalMilliseconds, localOnlyDecider, true) { } Widzimy, że oprócz wspomnianego wyrażenia lambda, możemy określić maksymalną liczbę prób oraz przedział czasowy. Wyświetl pełny artykuł
-
Czas szybko mija. Niedawno składałem CV do paru zachodnich firm, a tu już stuknęło 2,5 roku na emigracji w Hamburgu. 😀 Czas na małe podsumowanie tego czasu. Krótko o tym dlaczego właśnie emigracja Ciekawość. Pieniądze niby też lepsze (chociaż zdecydowałem się na pracę w małym startupie i zarabiałem zdecydowanie mniej niż w korporacji na podobnym […]Wyświetl pełny artykuł
-
Wszystkiego dobrego w 2016! Chce ktoś wstępnego pdf-a ebooka, który szykuję? Wystarczy podesłać mi pustego maila (albo maila z życzeniami noworocznymi, jeśli nie lubicie pustych maili ;)) na matt (at) javadevmatt.pl. Można się też dodać na listę mailingową po prawej stronie na tym blogu. Tam gdzie jest „Chcesz dostawać bonusy jako subskrybent? 😀 „. Osobom, […]Wyświetl pełny artykuł
-
Dwie sprawy, o których już pisałem na FB: 1. Udostępniłem wszystkie ilustracje z książki w trochę lepszej jakości (długi bok ustawiony na 1600 px). 2. W podpowiedzi we fladze Juliet jest drobny błąd, w związku z czym wrzuciłem pewną podpowiedź na stronę z flagami. Póki co tyle ;>Wyświetl pełny artykuł
-
Dwie sprawy, o których już pisałem na FB: 1. Udostępniłem wszystkie ilustracje z książki w trochę lepszej jakości (długi bok ustawiony na 1600 px). 2. W podpowiedzi we fladze Juliet jest drobny błąd, w związku z czym wrzuciłem pewną podpowiedź na stronę z flagami. Póki co tyle ;>Wyświetl pełny artykuł
-
W poprzednich postach o AKKA.NET pisałem o hierarchii aktorów. Stanowi ona bardzo ważny element systemów opartych na aktorach. Zasada jest taka, że uproszczamy problem na podproblmy, aż do momentu, gdy każdy podproblem jest łatwy w implementacji za pomocą pojedynczego aktora. Dla przypomnienia, stworzyliśmy następującą hierarchię: Co się stanie, gdy jeden z aktorów wyrzuci wyjątek? AKKA.NET posiada kilka mechanizmów. Przede wszystkim jednak, taki aktor zostanie wstrzymany, możliwe wraz ze wszystkimi potomkami (w zależności od przyjętej strategii). Następnie do rodzica zależy, co należy zrobić. Możliwe strategie to: Węzeł podrzędny zostanie wznowiony Węzeł podręczny zostanie zatrzymany Węzeł podręczny zostanie zrestartowany Rodzic może nie wiedzieć jak obsłużyć dany błąd. Z tego względu jest możliwość eskalacji problemu do kolejnego rodzica (czyli dziadka względem węzła, który wywołał problem). Dobór odpowiedniej strategi jest dość trudny i należy wiedzieć czym się charakteryzuje każda z nich. W przypadku wznowienia działania, stan wewnętrzny aktora jest utrzymany. Ponadto wszystkie dzieci danego węzła również zostaną wznowione. Dla odmiany restart aktora powoduje usunięcie całego stanu. Jeśli wiemy, że stan aktora jest błędny (niespójny), wtedy taka strategia jest rozsądna. Analogicznie potomkowie również zostaną zrestartowani. Przez stan wewnętrzny mam na myśli prywatne pola i zmienne. Kolejka z wiadomościami asynchronicznymi jest przechowywana gdzieś indziej. Jeśli zatem wiadomość “A” wywołała problem i zrestartowaliśmy aktora, wtedy kolejne wiadomości np. “B”, które były już w kolejce, nie zostaną utracone. Pominiemy wyłącznie wiadomość, która wywołała błąd. Analogicznie sytuacja wygląda z zatrzymaniem aktora. Jest to skrajna sytuacja, kiedy nie wiemy jak naprawić problem. Wtedy najbezpieczniej jest po prostu zatrzymać węzeł powodujący problem, wraz ze wszystkimi jego potomkami. Zasadę eskalacji błędu do rodzica, myślę, że można już wywnioskować ponieważ wygląda analogicznie. Węzeł jest wstrzymany tymczasowo w momencie przekazania kontroli do kolejnego rodzica. Implementacja obsługi błędów w AKKA.NET sprowadza się do tzw. “Supervision strategy”. Pierwsza, domyślna strategia to OneForOneStrategy. Oznacza to, że akacja zostanie podjęta wyłącznie na węźle, który spowodował problem. Załóżmy, że mamy rodzica P z dziećmi A, B, C. Jeśli wyjątek został wyrzucony przez “A”, wszelkie akcje (takie jak zatrzymanie, restart) zostaną podjęte na tylko A. AllForOneStrategy z kolei podejmie akcje dla każdego z rodzeństwa. Oznacza to, że jeśli A wywoła wyjątek to również B,C zostaną np. wstrzymane lub zrestartowane. Powyższe strategie również definiują jaki wyjątek jaką akcję powinien spowodować (stop, restart, escalate, resume). W praktyce wygląda to tak, że aktor zwraca swoją strategie, a strategia z kolei przyjmuje kilka parametrów określających możliwe akcje w zależności od wyjątku, liczby powtórzeń itp. W przyszłym wpisie, pokaże jak to wygląda od strony C#. Wyświetl pełny artykuł
-
W poprzednim poście opisałem zasadę działania protokołu HTTP Strict Transport Security. W skrócie najważniejsze punkty to: Serwer zwraca specjalny nagłówek “Strict-Transport-Security”, który powinien być przesyłany wyłącznie przez HTTPS. Po otrzymaniu nagłówka od serwera, przeglądarka zawsze będzie łączyć się przez HTTPS, a nie HTTP. Użytkownik jeśli nawet będzie chciał użyć HTTP, przeglądarka dokona wewnętrznego przekierowania na HTTPS (307 – internal redirect). Oczywiście można samemu zwracać odpowiedni nagłówek, ale lepiej skorzystać z gotowych pakietów nuget. Często programiści zawsze zwracają strict-transport-security, co jest również błędne – specyfikacja mówi wyraźnie, że powinno go zwracać się wyłącznie przez https. Skorzystamy zatem z pakietu NWebsec. Zestaw zawiera wiele różnych bibliotek związanych z bezpieczeństwem aplikacji webowych. W naszym przypadku zainteresowani jesteśmy wyłącznie HSTS. Po zainstalowaniu, wystarczy w OWIN startup: public class Startup { public void Configuration(IAppBuilder app) { app.UseHsts(options => options.MaxAge(seconds: 10886400).IncludeSubdomains().Preload()); } } Za pomocą FluentInterface możemy łatwo zmodyfikować każdy parametr nagłówka. Jeśli odpalimy teraz aplikacje, zobaczymy, że faktycznie nagłówek jest zwracany: Warto jednak wciąż wymuszać globalnie HTTPS za pomocą atrybutu RequiresHttpsAttribute: public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); filters.Add(new RequireHttpsAttribute()); } } Ważne to jest dla pierwszego odczytania HSTS oraz stanowi to drugą warstwę bezpieczeństwa (np. gdyby dana przeglądarka nie wspierała HSTS). Wyświetl pełny artykuł
-
P4CTF 2015 odbył się z miniony weekend i organizowany był przez polski zespół CTFowy p4, związany poniekąd z serwisem 4programmers.net (i który niedawno połączył się z innym polskim teamem - Amber Chamber). CTF ten można scharakteryzować tagami: single player, jeopardy, entry-level, online. W każdym razie po tym CTFie jest wysyp materiałów, zarówno od strony write-upów jak i informacji zza kulis. Linki poniżej - miłej lektury! • Statystyki i trochę kulis ← bardzo polecam w szczególności to • Write-upy i rozwiązania • Scoreboard + zadania (czyli strona CTF) Gratulacje dla akrasuski1 za top1, a także dla wszystkich, którzy wzięli udział i dzielnie walczyli! p4 - świetna robota z CTFem - do zobaczenia na CTFie Chaos Communication Congress za kilka dni!Wyświetl pełny artykuł
-
Krótki news: wyszedł nowy numer magazynu Programista (42) - można go znaleźć w Empiku / w prenumeracie / pisząc mejla do redakcji. Czytałem wcześniej (zaleta bycia recenzentem) dwa artykuły, które trafiły do tego numeru i które sądzę, że zainteresują czytelników mojego bloga: „Piszemy własny RTOS!” (Radosław Biernacki) oraz „HITCON CTF 2015 – Rsabin” (Jarosław Jedynak i Stanisław Podgórski z teamu p4). Ten pierwszy jest jednym z ciekawszych artykułów które czytałem w Programiście i traktuje o (jak nazwa wskazuje) pisaniu własnego systemu czasu rzeczywistego (w tym przypadku w kontekście platformy AVR, ale większość kodu jest uniwersalna / kompatybilna z x86). Ten drugi jest natomiast solidnym write-upem o wysoko punktowanym zadaniu z kategorii crypto z HITCON CTF 2015 - zdecydowanie polecam. Przydatne linki: Spis treści "Teaser" artykułu o RTOS I póki co tyle - miłej lektury!Wyświetl pełny artykuł
-
Protokół HTTPS jest dzisiaj powszechny na wszystkich stronach z wrażliwymi informacjami. Banki są klasycznym przykładem. HTTPS “gwarantuje”, że dane są przesyłane w szyfrowanej formie, a klient wie, że łączy się z oryginalną stroną. Certyfikat publikowany przez stronę jest gwarantem, że korzystamy właśnie z tej aplikacji, z której zamierzaliśmy. W najprostszej postaci wygląda to zatem następująco: Tego przynajmniej spodziewamy się… Problem w tym, że czasami użytkownicy wpisują adres http://… W takich sytuacjach, programiści przekierowują użytkownika na HTTPS, tzn. sekwencja wygląda następująco: Użytkownik wpisuje adres http://www.domain.com Serwer zwraca kod 302 – przekierowanie na https://www.domain.com Przeglądarka od teraz korzysta z bezpiecznej wersji czyli https://www.domain.com Wygląda więc to następująco: Niestety jest to bardzo niebezpieczna architektura. Bardzo dużo stron, włączając w to banki, korzysta z przekierowania na HTTPS. Wiele banków korzysta z HTTP na stronie głównej, a do HTTPS jest użytkownik przełączony dopiero w momencie chęci zalogowania do strony. Oznacza to, że strona główna banku jest niebezpieczna. Wszystko co na niej znajduje się może zostać podrobione (brak certyfikatu). Jeśli ktoś podmieni stronę główną i wstawi np. link do logowania do kompletnie innej strony, możliwe, że staniemy się ofiarą phishing. Wyobraźmy sobie, że korzystamy z Internetu w miejscu publicznym, np. używając WIFI. Możliwe, że ktoś wstawi proxy między nami, a docelowymi stronami. Co jeśli staniemy się ofiarą ataku man in the middle? Taki serwer proxy będzie w stanie przekierowywać wszystkie nasze żądania. Wtedy powyższa sekwencja może wyglądać już tak: Użytkownik wpisuje http://www.domain.com Man in the middle przechwytuje żądanie i zwraca jakąkolwiek treść.. Użytkownik nie zauważa nic podejrzanego. Strona wygląda identycznie – jesteśmy ofiarami phishing. Czujny użytkownik zauważy, że po kliknięciu loguj na stronie głównej banku nie został przekierowany do https i wciąż korzysta z nieszyfrowanego protokołu. Niestety jest to rzadkość. Problem jest jeszcze większy, ponieważ MITM (man in the middle), może rzeczywiście logować się do banku. Użytkownik poda hasło poprzez HTTP do MITM, a potem MITM nawiąże połączenie szyfrowane HTTPS z prawdziwą stroną banku. Możliwe jest zatem, że użytkownik będzie widział prawdziwe dane (balans konta itp), ale wszystko serwowane będzie przez MITM, który łączy się poprzez HTTPS z prawdziwym bankiem, a potem przekierowuje wszystko w postaci HTTP do użytkownika. Rozwiązanie składa się z dwóch etapów. Przede wszystkim każdy bank powinien w pełni implementować HTTPS – na każdej podstronie. Druga kwestia jest trudniejsza. Użytkownicy wciąż domyślnie będą wpisywać www.domain.com, a nie https://www.domain.com. Jak już wiemy, przekierowanie jest niebezpieczne bo nie wiadomo, czy ktoś po drodze nie przechwyci zapytania i nie będzie “karmił” nas dowolnymi danymi. Z tego względu, wymyślono protokół HSTS (HTTP Strict Transport Security). Jest to protokół implementowany bezpośrednio przez przeglądarki. Jeśli serwer ustawi odpowiedni nagłówek, wtedy przeglądarka jest zobowiązana łączyć się zawsze przez HTTPS, a nie HTTP. Dzięki temu, MITM jest nie możliwy, ponieważ nigdy nie dojdzie do połączenia HTTP, a jak wiemy, dane przesyłane przez HTTPS nie mogą być zmodyfikowane. Aby przeglądarka łączyła się zawsze przez https, serwer strony musi zwrócić następujący nagłówek w odpowiedzi: Strict-Transport-Security:max-age=631138520; includeSubDomains; preload Parametr max-age oznacza, jak długo przeglądarka ma łączyć się zawsze przez https. Powyższy nagłówek zawsze należy zwracać przez HTTPS, a nie przez HTTP. Wynika to z prostego faktu, że przeglądarka nie może ufać niczemu, co pochodzi z HTTP. Łatwo wyobrazić sobie, że przez HTTP, MITM modyfikuje np. max-age do 1. Sekwencja może zatem teraz wyglądać następująco: 1. Użytkownik wpisuje http://www.domain.com 2. Serwer zwraca 302 oraz https://www.domain.com 3. Przeglądarka łączy się z https://www.domain.com 4. Serwer zwraca nagłówek Strict-transport-security. 5. Użytkownik wpisuje http://www.domain.com 6. Przeglądarka automatycznie przekierowuje na https://www.domain.com (kod 307, internal redirect). Od teraz MITM nie jest w stanie nam zaszkodzić, ponieważ nie wychodzi żadne połączenie HTTP. Powyższe rozwiązanie ma jednak wciąż pewną lukę.Pierwsze połączenie HTTP wciąż jest niebezpieczne. Co prawda minimalizuje to groźbę ataku MITM ponieważ wystarczy, że użytkownik chociaż raz wcześniej korzystał ze strony (tak, że HSTS został ustawiony). Niestety w skrajnej sytuacji, wciąż mamy ten sam problem (MITM i pierwsze zapytanie z danej przeglądarki). Z tego względu mamy tzw. pre-loaded lists. Przeglądarki korzystają z tych list i wtedy każda strona, która na niej znajduje się, będzie ładowana automatycznie wyłącznie przez HTTPS. Możemy naszą stronę dodać tutaj. Po dodaniu do listy, przeglądarki będą łączyć się automatycznie przez HTTPS, nawet za pierwszym razem. Możemy również zobaczyć adresy aktualnie dodanych stron do tych list. W następnym wpisie, pokażę jak zaimplementować HSTS w ASP.NET MVC. W międzyczasie zachęcam zapoznać się z kompatybilnością różnych przeglądarek z HSTS . Wyświetl pełny artykuł
-
Postfix templates to kolejne usprawnienie, dzięki któremu nie musimy korzystać co chwilę z myszki i skakać między liniami kodu. Postfix templates mają za zadanie uniknięcie cofania się kursorem do początku linii. Na przykład, jeśli definiujemy warunek, wtedy jeśli chcemy dodać IF, musimy cofnąć się. Podobnie z pętlami, using, lock i innymi konstrukcjami. Postfix oznacza, że szablon aplikujemy na końcu linii. Postfix templates zostało zintegrowane z Resharper 10.0. Mój ulubiony szablon to “.var”. Bardzo często deklarujemy zmienne w następujący sposób: var stringBuilder = new StringBuilder(); Za pomocą szablonów możemy napisać “StringBuilder.var” i zostanie wygenerowany powyższy kod. Ponadto, Intellitrace podpowie nam StringBuilder więc tak naprawdę będziemy musieli napisać coś w stylu “Str.var”. Screenshot: Po naciśnięciu enter, zostanie wygenerowany kod: Oczywiście trochę to zajmie czasu, aby zapamiętać wszystkie skróty szablonów oraz przyzwyczaić się do nich. Na szczęście są one na tyle wygodne, że po pewnym czasie stają się tak naturalne, jak “alt+enter”. Jeśli chcemy wyrzucić wyjątkiem wtedy wpisujemy: Szablon wygeneruje oczywiście: threw new NotImplementException(); Proszę zwrócić uwagę, że pierwsza cześć jest zawsze silnie typowana. Oznacza to, że w praktyce wystarczy, że naciśniemy kilka klawiszy i wyjątek zostanie wyrzucony (szczególnie, że nie ma spacji między nazwą wyjątku, a .throw). Wsparcie intellitrace jest jeszcze bardziej przydatne. Kolejny przydatny szablon to .if. Najpierw piszemy warunek, np. a>5, a potem za pomocą .if wygenerujemy instrukcję warunkową: Do dyspozycji mamy również różne typy pętli. Szczególnie interesującą jest .forr, czyli for iterujący od końca do początku tablicy: Wygenerowany kod: for (var i = data.Length - 1; i >= 0; i--) { } Z ciekawszych skrótów jest jeszcze: .null,.notnull czy .switch. Pełna lista szablonów znajduje się tutaj. Nie chcę tutaj opisać każdej instrukcji osobno bo najlepiej po prostu popraktykować to samemu – na początku jest trudno przyzwyczaić się. Wyświetl pełny artykuł
-
Bardzo krótki news: wrzuciłem wersję bardzo-alpha serwisu książki; póki co można tworzyć konta i wrzucać flagi. Zachęcam do testów - https://zrozumiecprogramowanie.pl/ (HTTPS only). W następnym tygodniu postaram się podpiąć kolejną część serwisu (erraty). I tyle.Wyświetl pełny artykuł
-
Czasami w widoku wywołujemy funkcję JavaScript z parametrami, które są przekazane za pomocą ViewModel z kontrolera. Załóżmy, że nasza metoda w kontrolerze wygląda następująco: public ActionResult Index() { return View(new FooModel("Hello World!")); } ViewModel z kolei zawiera jedną właściwość: public class FooModel { public string Text { get; set; } public FooModel(string text) { Text = text; } } Następnie zdefiniujmy jakąkolwiek funkcję JS przyjmującą parametry: <script type="text/javascript"> function doSomethingInJs(text) { $('#sampleContainer').html(text); } </script> Błędne wywołanie funkcji w razor wygląda z kolei następująco: <script type="text/javascript"> doSomethingInJs('@Model.Text'); </script> Jest to nic innego, jak klasyczny przykład wstrzyknięcia złośliwego kodu. Dotyczy to wszystkich pól typu string. Nawet jeśli spodziewamy się tylko imienia czy nazwiska, nigdy nie wiadomo jakie dane zawiera view model. Zwykle dane pochodzą z bazy danych. Co jeśli w jakiś sposób, baza danych zawiera już złośliwy kod? Aplikacja powinna traktować wszystkie dane, jako potencjalne zagrożenie. Co jeśli, następująca treść zostanie przekazana? public ActionResult Index() { return View(new FooModel("<script>alert('Hello World')</script>")); } Na szczęście powyższy kod jest bezpieczny, ponieważ Razor zamieni <script> na znaczniki HTML: <script type="text/javascript"> $(function() { doSomethingInJs('<script>alert('Hello World')</script>'); }); </script> Innymi słowy, kod zostanie wyświetlony jak zwykły tekst. Za każdym razem, jak wywołujemy @Model, zawartość jest enkodowana. Co jednak stanie się, jeśli treść zostanie przekazana jako ASCII HEX? public ActionResult Index() { var text = "\\x3c\\x73\\x63\\x72\\x69\\x70\\x74\\x3e\\x61\\x6c\\x65\\x72\\x74\\x28\\x27\\x48\\x65\\x6c\\x6c\\x6f\\x20\\x57\\x6f\\x72\\x6c\\x64\\x27\\x29\\x3c\\x2f\\x73\\x63\\x72\\x69\\x70\\x74\\x3e"; return View(new FooModel(text)); } Razor nie zakoduje treści ponieważ jest to zwykły tekst (brak znaczników HTML). Javascript z kolei, rozpoznaje ASCII w postaci hex (za pomocą \x). Efekt będzie taki, że kod javascript wykona się i wyświetli alert. W tej chwili, jeśli zajrzymy do źródła strony, zobaczymy: <script type="text/javascript"> $(function() { doSomethingInJs('\x3c\x73\x63\x72\x69\x70\x74\x3e\x61\x6c\x65\x72\x74\x28\x27\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x27\x29\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e'); }); </script> Rozwiązaniem jest endkodowanie parametrów funkcji JavaScript za pomocą HttpUtility.JavaScriptStringEncode: <script type="text/javascript"> $(function() { doSomethingInJs('@HttpUtility.JavaScriptStringEncode(Model.Text)'); }); </script> Efektem będzie: <script type="text/javascript"> $(function() { doSomethingInJs('\\x3c\\x73\\x63\\x72\\x69\\x70\\x74\\x3e\\x61\\x6c\\x65\\x72\\x74\\x28\\x27\\x48\\x65\\x6c\\x6c\\x6f\\x20\\x57\\x6f\\x72\\x6c\\x64\\x27\\x29\\x3c\\x2f\\x73\\x63\\x72\\x69\\x70\\x74\\x3e'); }); </script> Widzimy, że każdy kod ascii, zostały poprzedzony dodatkowym znakiem ‘\’. Generalnie połączenie jQuery + mieszanie C# z JavaScript jest nie tylko złą praktyką z punktu widzenia bezpieczeństwa, ale również nie jest to zbyt czysty kod. Nie powinno mieszać się kodu inline z szablonami razor. Te dwie warstwy powinny rozwijać się niezależnie. Da nam to nie tylko łatwiejszy w utrzymaniu kod, ale również jak widać powyżej, łatwiej będzie uniknąć luk w bezpieczeństwie. Wyświetl pełny artykuł
-
New version of wow64ext library is available for download: http://rewolf.pl/stuff/rewolf.wow64ext.v1.0.0.8.zipor if someone prefer github:https://github.com/rwfpl/rewolf-wow64ext Changelog Fixed elusive bug that appears only on AMD cpus Removed VS CRT dependencies – dll size shrank to 9kB (previously 41kB) Added sanity checks, so x64 switch won’t run on x86 OS More details AMD case is really interesting as […]Wyświetl pełny artykuł
-
Nadal w temacie książki - trzy newsy (a w zasadzie dwa i brak newsa): e-book (Mobi, EPUB) "Zrozumieć Programowanie" jest "już" dostępny (nie jest źle, tylko tydzień opóźnienia) - szybki link do ibuk.pl (gdzie obecnie jest najtaniej wg moich informacji - o tym "dlaczego" napiszę więcej w treści posta); wydawca udostępnił również jeden pełen rozdział książki ("Procesy") do pobrania w formie Mobi/EPUB/PDF (trzeba podać maila) - szybki link do it.pwn.pl; a serwisu jak nie było, tak nie ma - TL;DR: niestety tylko w weekendy obecnie mam czas, żeby przy nim siedzieć; liczyłem, że w zeszły weekend uda się coś już wrzucić, ale wygląda na to, że dopiero w nadchodzący uda się to faktycznie zrobić. A teraz jeszcze raz to samo... E-book "Zrozumieć Programowanie Jest dostępny do kupienia w formacie Mobi+EPUB (nie, nie ma PDFa). Wg moich informacji najtaniej obecnie jest na ibuk.pl (30 PLN); na koniec miesiąca cena ma podskoczyć do rynkowej (56 PLN). Kontekst zniżki na ibuk.pl jest dość ciekawy i ma związek z problemami technicznymi (o czym już wspominałem na FB) - oryginalnym zamierzeniem było zaoferować zniżkę osobom, które kupiły papierowy egzemplarz w przedsprzedaży (w ramach podziękowania za zaufanie aka kupowanie kota w worku). Ale, okazało się, że istniejący serwis nie ma możliwości wprowadzenia kuponów/kodów rabatowych - ups (opcji nie ma, będzie kiedyś). Więc wydawca zrobił chyba najlepsze co mógł w tej sytuacji, tj. zrobił po prostu zniżkę.[słownie: kropka] Tak więc do końca miesiąca jest 30 PLN. Btw, od razu zaadresuje uwagę, która na FB się pojawiła - tj. że w sumie fajnie by było, gdyby e-book był dodawany do egzemplarza papierowego za darmo lub np. za 10% ceny. Mi pomysł się bardzo podoba (przy czym ja nie jestem wydawnictwem, które musi się jakoś utrzymać ;p), natomiast nie pomyślałem o tym zupełnie jak pracowałem nad umową, więc wyszło jak wyszło (też nie jest powiedziane, że wydawnictwo by na to poszło nawet jeśli bym o tym pomyślał). Proponuje natomiast aby osoby zainteresowane takimi rozwiązaniami pojawiającymi się w przyszłości wysłały mejla do wydawnictwa z uwagami na ten temat (serio - te mejle są czytane). Ah, wracając jeszcze do tematu e-booków - okazuje się (o czym chyba ktoś w komentarzach nawet już pisał), że na ibuk.pl można również "wypożyczyć" ebooka na N dni (z tego co widzę: 5 PLN za 24h, 7 PLN za 7 dni itd) - dostęp do niego wtedy jest via czytnik WWW, który jest całkiem niezły technicznie (chwilę patrzyłem co tam w JS się dzieje). Udostępniony rozdział - "Procesy" Tutaj: http://it.pwn.pl/Raporty/Zrozumiec-programowanie-procesy (Mobi, EPUB, PDF) Podobnie jak było w przypadku Programistycznych Potknięć, trzeba podać adres e-mail. Btw, jest tam pewien już-zgłoszony bug - jeśli podacie e-mail z tagiem, np asdf+xyz@example.com, to link-który-dostajecie-na-mejla jest uszkodzony. Good news: łatwo go naprawić - po kliknięciu w URL zobaczycie podany adres e-mail - trzeba tam dodać %2B (czyli znak + zakodowany w tzw. URL encoding) w miejscu gdzie powinien być plus. Jak pisałem, bug już zgłoszony, być może niedługo będzie fix. Gdzie. Jest. Serwis. ?!?!? Chciałbym Was bardzo przeprosić za opóźnienia - niestety tylko weekendami mam czas przy nim siedzieć, więc się trochę przeciągnęło. To, że serwis jest pięknym przykładem over-engineeringu to inna sprawa - korci mnie, żeby potem nagrać eps podcastu typu "przewodnik po labiryncie jakim jest ten serwis" albo "serwis książki - jak go NIE robić". Niemniej jednak optymistycznie liczę, że uda mi się coś już wrzucić w najbliższą niedzielę na serwer i zacząć wypełniać erratę. A potem wrócić do podcastów (mam nowy mikrofon btw - Blue Yeti Pro - za rekomendacją Macieja z DevTalk; jest świetny). I tyle.Wyświetl pełny artykuł
-
W poprzednim poście użyliśmy metody ActorSelection w celu uzyskania referencji do aktora: var actor1 = system.ActorSelection("/user/ApplicationUserControllerActor/Piotr") Dzisiaj chciałbym bardziej skupić się na definiowaniu ścieżki do aktora. Pełna ścieżka może zawierać następujące elementy: – protokół – nazwa systemu – adres ip aktora – seria nazw aktorów opisująca hierarchie np. ApplicationUserControllerActor/actor1/actor2 itp. Załóżmy, że nasz aktor znajduje się na innym komputerze. Oznacza to, aby wysłać jakieś wiadomości do niego musimy skorzystać z protokołu sieciowego. Nazwa ścieżki będzie wtedy wyglądać: akka.tcp://FooHierarchySystem@89.124.43.14/user/ApplicationUserControllerActor/Piotr Jeśli nie korzystamy ze zdalnych aktorów, wtedy moglibyśmy napisać: akka://FooHierarchySystem/user/ApplicationUserControllerActor/Piotr W poprzednim poście jednak nie musieliśmy podawać nazwy systemu (FooHierarchySystem). Wynika to z faktu, że akka .net wspiera ścieżki relatywne. ActorSlection wywoływaliśmy bezpośrednio na systemie, zatem nie było potrzeby precyzowania tego w ścieżce. Można to porównać do ścieżek relatywnych występujących w systemie plików. Załóżmy, że jesteśmy teraz w aktorze ApplicationUserControllerActor i hierarchia jest taka sama jak w poprzednim wpisie: W celu uzyskania dostępu do jednej z instancji ApplicationUserActor możemy: // Pierwsze podejście Context.ActorSelection("akka://FooHierarchySystem/user/ApplicationUserControllerActor/Piotr"); // Drugie podejście Context.ActorSelection("user/ApplicationUserControllerActor/Piotr"); // Trzecie podejście Context.ActorSelection("Piotr"); Wszystkie ścieżki wskazują na tego samego aktora, a dwie ostatnie są relatywne. Podobnie z ApplicationUserControllerActor możemy: Context.ActorSelection("../../ApplicationUserControllerActor").Tell(new AddUser("AnotherUser")); Tak jak w ścieżkach systemu plików, ../ oznacza wejście o jeden poziom do góry. W powyższym przykładzie ../../ da nam referencję na /user, a potem schodzimy z powrotem na ApplicationUserControllerActor. Wyświetl pełny artykuł
-
Tak kronikarsko.Wyświetl pełny artykuł
- Poprzednia
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- Dalej
-
Strona 2 z 9