Interceptor dla WCF-a

Ostatnio programując w javie (sic!) spodobała mi się jedna rzecz, którą chciałem wprowadzić do swoich projektów w .NET, a mianowicie Interceptor. Pozwala on w prosty sposób udekorować metodę własną logiką i to wszystko za pomocą jednej adnotacji. Podobną funkcję spełniają ActionFilter w ASP.NET MVC. Ja natomiast chciałem dodać warstwę logowania do metod WCF-a, więc zacząłem szukać. Niestety nie znalazłem nic co działałoby równie dobrze co Javowe interceptory, więc postanowiłem napisać coś samemu.

Przede wszystkim chciałem aby taki interceptor można było zakładać właśnie za pomocą atrybutu (albo na pojedynczą operację albo na cały serwis). Rezultatem mojej twórczości została taka oto klasa.

public class WCFInterceptor : Attribute, IOperationBehavior, IServiceBehavior
{
    private Type actionType;

    public WCFInterceptor(Type actionType)
    {
        if (actionType == null)
            throw new ArgumentException("Type cannot be null");

        if (!actionType.GetInterfaces().Contains(typeof(IParameterInspector)))
            throw new ArgumentException("Type must implement IParameterInspector");

        this.actionType = actionType;
    }

    #region IOperationBehavior Members

    //...

    void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, 
        DispatchOperation dispatchOperation)
    {
        try
        {
            IParameterInspector actionInstance = (IParameterInspector)Activator.CreateInstance(this.actionType);
            dispatchOperation.ParameterInspectors.Add(actionInstance);
        }
        catch
        {
            throw new ArgumentException(string.Format("Could not create instance of type: {0}", this.actionType.Name));
        }
    }

    #endregion

    #region IServiceBehavior Members

    // ... 

    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
        {
            foreach (var operation in endpoint.Contract.Operations)
            {
                operation.Behaviors.Add(this);
            }
        }
    }

    #endregion
}

Jako parametr w konstruktorze przyjmuje on typ klasy, która musi implementować IParameterInspector, jest to prosty interfejs, który wymaga zaimplementowania dwóch metod: AfterCall oraz BeforeCall. Główną przyczyną, dla której chciałem stworzyć taki interceptor było logowanie wejścia i wyjścia z operacji, dlatego dodatkowo stworzyłem klasę LogInterceptorAction, która może zostać przesłana w konstruktorze atrybutu.

public class LogInterceptorAction : IParameterInspector
{
    private readonly ILog log = LogManager.GetLogger(typeof(LogInterceptorAction));

    public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
    {
        log.Debug(string.Format("EXIT {0} returns {1}", GetMethodnameWithParameters(operationName, outputs), returnValue));
    }

    public object BeforeCall(string operationName, object[] inputs)
    {
        log.Debug(string.Format("ENTER {0}", GetMethodnameWithParameters(operationName, inputs)));
        return null;
    }

    private string GetMethodnameWithParameters(string operationName, object[] outputs)
    {
        var sBuilder = new StringBuilder();
        sBuilder.Append(operationName).Append("(");
        if (outputs != null)
        {
            sBuilder.Append(string.Join(",", outputs));
        }
        sBuilder.Append(")");

        return sBuilder.ToString();
    }
}

Aby udekorować nasz serwis takim interceptorem wystarczy obok atrybutu OperationContract lub ServiceContract, dodać nasz własny WCFInterceptor

[ServiceContract]
[WCFInterceptor(typeof(LogInterceptorAction))]
public interface IService1
{
    //...
}

lub jeśli chcemy zastosować to tylko do jednej operacji

[OperationContract]
[WCFInterceptor(typeof(LogInterceptorAction))]
string GetData(int value);

Zaimplementowane podejście trochę różni się od tego co jest w javie, przede wszystkim nie mamy tutaj podejścia jak z metody szablonowej, gdzie możemy wykonać operacje WCF-a w dowolnym momencie. Możliwe, że rozwiązanie mojego problemu już istnieje i niepotrzebnie wymyślałem koło od nowa, tak więc jeśli znacie jakąś klasę/bibliotekę, która mogłaby się przydać w przyszłości, dajcie znać w komentarzach. 🙂

Splash screen with shadow

Zawsze chciałem coś takiego zrobić, a do tej pory nie wiedziałem że jest to możliwe. Efekt możecie zobaczyć poniżej, a do zrobienia takiego splash screena użyłem tylko tego co daje nam podstawowy WPF. W zasadzie bazując na tym rozwiązaniu można tworzyć aplikacje, rzucające cień na pulpit (czego bardzo mi brakuje w Windows 8).

 splashscreen

Sam efekt jest bardzo prosty do osiągnięcia i wszystko można zapisać w XAMLu.

<Window x:Class="SplashScreenApp.SplashScreen"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="350" Width="225" 
        WindowStyle="None" 
        AllowsTransparency="True" 
        Background="Transparent"
        WindowStartupLocation="CenterScreen"
        ShowInTaskbar="False">
    <Grid Background="Transparent">
        <Grid Margin="15" Background="#252526">
            <Grid.BitmapEffect>
                <DropShadowBitmapEffect Direction="-90" Softness="15" ShadowDepth="1" />
            </Grid.BitmapEffect>
            <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
                <TextBlock Text="My App" Foreground="White" FontSize="30"  />
                <TextBlock Text="v.1.0" Foreground="White" FontSize="10"  />
            </StackPanel>
        </Grid>
    </Grid>
</Window>

To co tutaj najważniejsze to:

WindowStyle=”None” – usuwa ramki z okna
AllowsTransparency=”True” – pozwala na przezroczystość wewnątrz okna
WindowStartupLocation=”CenterScreen” – ustawiamy pozycje startową okna na środek ekranu
ShowInTaskbar=”False” – chowamy okno z taskbara

No i najważniejsze czyli tworzymy grida wewnątrz grida, dając lekki margines dla wewnętrznego elementu i dla niego też tworząc DropShadowBitmapEffect. Oszukujemy więc trochę bo nasze okno jest takie duże jak okno wraz z cieniem, ale całość wyszła bardzo ładnie :)

Ewolucja Windows Phone

Od kilku dni mam przyjemność bawić się najnowszą aktualizacją Microsoftu na systemy mobilne, czyli wp_ss_20140522_0001-180x300Windows Phone 8.1. Muszę powiedzieć, że to dla mnie ogromny przeskok, ponieważ nie miałem okazji użytkować, na co dzień poprzedniej wersji (8.0). Przesiadka z 7.8 na 8.1 robi na prawdę ogromne wrażenie. Na pierwszy rzut oka widać podobieństwa do Windows 8.1, o których trochę później.
Na początek zmiana, która najbardziej rzuca się w oczy, czyli dodatkowa kolumna na swoje kafelki. Dzięki temu odblokowując telefon widzimy o wiele więcej informacji niż we wcześniejszych wersjach. Muszę przyznać, że na początku najmniejsze kafelki wydawały mi się zbyt małe i ciężko jest czasami w nie trafić, ale po pewnym czasie można się przyzwyczaić i już tak nie przeszkadza. Nie polecam ustawiać tych małych kafelków w prawym górnym rogu, bo czasami trudno tam sięgnąć ;) Ciekaw jestem tylko jak będzie wyglądać to na telefonach z mniejszym ekranem, czy tam miniaturowe kafelki zdadzą egzamin.
Następnym ukłonem w stronę użytkowników, jest centrum powiadomień, o które wiele osób się upominało. Centrum powiadomień zbiera wszystkie notyfikacje, które wcześniej były pokazywane w formie toastów. Dodatkowym plusem jest możliwość ustawienia sobie 4 skrótów, do najczęściej wykonywanych akcji. Na chwile obecną mamy 11 akcji, niestety zewnętrzne aplikacje nie mogą się podpiąć pod te skróty, więc niestety zostanie to w miarę ułomne.

wp_ss_20140522_0005-300x213Jeśli chodzi o same aplikacje to dostajemy całą paletę aplikacji, dostępnych już na Windows 8.1, takich jak PDF Reader, Finanse, Wiadomości, Pogoda itp. wydaje mi się jednak, że były one już dostępne w Windows Phone 8, więc nie będę się zbytnio o nich rozpisywał. Nowinką, na którą wszyscy czekali jest za to Cortana, która jak sama o sobie mówi jest naszym prywatnym asystentem, który stara się ułatwić nam pracę z telefonem.

wp_ss_20140522_0007-300x103Czy tak jest na prawdę? Mam podzielone zdanie, przede wszystkim muszę wspomnieć że Cortana jest jeszcze w fazie beta, więc rozumiem, że wiele rzeczy jeszcze programiści w Microsoft ją nauczą. Na razie poza rzeczami pokazanymi na konferencji build ciężko znaleźć chwile, żeby Cortana nas zaskoczyła. Większość zapytań wrzuca do binga i wyszukuje. Natomiast świetnie radzi sobie ze wszelkiego rodzaju datami i przypomnieniami. Świetną rzeczą jest możliwość przypomnienia o czymś następnym razem, gdy będziemy rozmawiać z daną osobą. Widać również, że Microsoft nauczył się w końcu, że wielka potęga drzemie w programistach i dał możliwość integracji własnych aplikacji z Cortaną.

Jeśli chodzi o sam wygląda aplikacji, to też został trochę zmieniony. Znaną już wszystkim Panoramę, zastąpił Hub, który jest w zasadzie tym samym, tylko inaczej wystylizowanym i pozwalającym na pokazanie większej ilości contentu. Poniżej stara panorama z lewej i nowa kontrolka z prawej.

wp_ss_20140522_0004-180x300wp_ss_20140522_0008-180x300

To tyle, jeśli chodzi o stronę użytkową nowego systemu, jeśli chodzi o stronę programistyczną to zmian jest o wiele więcej i
sam jeszcze nie znam wszystkich. Dopiero zaczynam oglądać nowości na różnych prezentacjach i samplach. Jak to zwykle przy nowych produktach Microsoft nakręcił już Building Apps for Windows Phone 8.1 Jump Start, czyli kurs online przedstawiający tworzenie aplikacji na Windows Phone 8.1 praktycznie od podstaw. Można go już oglądać na Channel 9.

Podsumowując moje kilkudniowe przygody z Windows Phone 8.1. Cieszę się, że Microsoft przestał robić rewolucje w swoich systemach a zaczął proces ewolucji. Dzięki temu miejmy nadzieję czekają nas dojrzałe systemy Windows 9 i Windows Phone 9.

IAESTE CaseWeek 2014

Caseweek to ogólnopolska inicjatywa studentów ze stowarzyszenia IAESTE. W tym roku po raz pierwszy inicjatywa ta zawitała również do Łodzi. Jako przedstawiciel firmy Cybercom miałem możliwość poprowadzenia warsztatów z tworzenia aplikacji Modern UI. Poniżej znajduje się prezentacja, kody źródłowe poszczególnych kroków można pobrać tutaj.

Wkrótce postaram się dodać, krótki opis poszczególnych kroków, chociaż większość rzeczy napisałem już na blogu.

Autentykacja za pomocą Azure Mobile Services

Tworząc trzecią część artykułu o tworzeniu logiki współdzielonej stwierdziłem że materiału będzie trochę za dużo jak na jeden post, dlatego postanowiłem część zapisać w tym poście. O czym będzie dzisiaj? Przede wszystkim o tym jak rozszerzyć możliwość autentykacji jaką daje nam WAMS (Windows Azure Mobile Services). Czasami bowiem poza tym że chcemy wiedzieć czy użytkownik posiada konto w danym serwisie, chcemy również poznać jego imię, czy zapisać sobie jego avatar.

Pierwszym co musimy zrobić to wygenerować sobie odpowiednie klucze do serwisu z którego będziecmy chcieli skorzystać. Microsoft zapewnia nam instrukcje jak wygenerować te klucze dla:

* – mała wskazówka: po wygenerowaniu kluczy wchodzimy w zakładkę “Status & Review” i zaznaczamy checkbox “Do you want to make this app and all its live features available to the general public?” na Tak. Pozwoli to na logowanie innych użytkowników, nie tylko użytkownika, który stworzył aplikacje ;)

** – z powodu że api google się zmieniło, tutorial jest nieaktualny, możliwe że go zaktualizują w przyszłości.

Mając już wygenerowane klucze możemy dodać autentykacje do naszej aplikacji. Jeśli wszystko pójdzie dobrze i użytkownik zaloguje się na poprawne konto dostaniemy jego UserId. Możemy więc dodać go sobie do naszej bazy danych przy okazji wyciągając inne dane. Przechodzimy zatem do naszego panelu Azure Mobile Services, tworzymy nową tabelkę Users i dajemy pozwolenie na dodawanie tylko zalogowanym użytkownikom.

blog-wams-users-table

Następnie Dodajemy sobie kolumny Name oraz AvatarUrl (obie są stringami). Na koniec przechodzimy na zakładkę Script i podmieniamy skrypt Insert na przedstawiony poniżej.

function insert(item, user, request) {
    var req = require('request');

    var getFacebookPic = function()
    {
        var facebookId = user.userId.replace("Facebook:", "");
        var facebookReqOptions = {
                    uri: 'http://graph.facebook.com/' + facebookId + '?fields=picture.type(small)',
                    headers: { Accept: "application/json" }
                };
        req(facebookReqOptions, function(err, resp, body){
            var jsonBody = JSON.parse(body);
            item.AvatarUrl = jsonBody.picture.data.url;
        });
    }

    var getMicrosoftPic = function(userId){
        var link = 'https://cid-[userId].users.storage.live.com/users/0x[userId]/myprofile/expressionprofile/profilephoto:Win8Static,UserTileMedium,UserTileStatic';
        item.AvatarUrl = link.replace(/[userId]/g, userId);       
    }

    item.Nick = "<unknown>"; // default
    user.getIdentities({
        success: function (identities) {
            var msToken;
            var url = null;
            var oauth = null;
            if (identities.google) {
                var googleAccessToken = identities.google.accessToken;
                url = 'https://www.googleapis.com/oauth2/v3/userinfo?access_token=' + googleAccessToken;
            } else if (identities.facebook) {
                var fbAccessToken = identities.facebook.accessToken;
                url = 'https://graph.facebook.com/me?access_token=' + fbAccessToken;
            } else if (identities.microsoft) {
                var liveAccessToken = identities.microsoft.accessToken;
                url = 'https://apis.live.net/v5.0/me/?method=GET&access_token=' + liveAccessToken;
                msToken = liveAccessToken;
            } else if (identities.twitter) {
                var userId = user.userId;
                var twitterId = userId.substring(userId.indexOf(':') + 1);
                url = 'https://api.twitter.com/1.1/users/show.json?user_id=' + twitterId;
                var consumerKey = process.env.MS_TwitterConsumerKey;
                var consumerSecret = process.env.MS_TwitterConsumerSecret;
                oauth = {
                    consumer_key: consumerKey,
                    consumer_secret: consumerSecret,
                    token: identities.twitter.accessToken,
                    token_secret: identities.twitter.accessTokenSecret
                };
            }

            if (url) {
                var requestCallback = function (err, resp, body) {
                    if (err || resp.statusCode !== 200) {
                        console.error('Error sending data to the provider: ', err);
                        request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
                    } else {
                        try {
                            var userData = JSON.parse(body);
                            item.Nick = userData.name;
                            if (identities.twitter) {
                                item.AvatarUrl = userData.profile_image_url;
                            } else if (identities.facebook){
                               getFacebookPic();
                            } else if (identities.microsoft){
                               getMicrosoftPic(userData.id);
                            }
                            request.execute();
                        } catch (ex) {
                            console.error('Error parsing response from the provider API: ', ex);
                            request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
                        }
                    }
                }

                var reqOptions = {
                    uri: url,
                    headers: { Accept: "application/json" }
                };
                if (oauth) {
                    reqOptions.oauth = oauth;
                }
                req(reqOptions, requestCallback);
            } else {
                // Insert with default user name
                request.execute();
            }
        }
    });

}

Skrypt ten zapisuje nazwę użytkownika w polu Name, oraz dla autentykacji poprzez Facebooka, Twittera oraz Microsoft Account zapisuje link do avatara. Niestety dla Google Account nie mogłem wygenerować kluczy więc nie miałem jak sprawdzić skąd wyciągnąć avatar.

Tworzenie logiki współdzielonej cz. 2 – MVVM

W poprzednim poście mówiłem o nowym rodzaju biblioteki, jakim jest Portable Class Library. Microsoft przedstawił nam takie rozwiązanie, jeśli chodzi o tworzenie logiki aplikacji mobilnych, do którego musimy się dostosować. W poniższym poście pokaże na przykładzie, że nie jest to takie straszne, a tworzenie logiki za pomocą PCL’a może być całkiem miłe.

Wspominałem wcześniej, że do PLC-a możemy przenieść część naszych ViewModeli, jeśli są one jednakowe w obu aplikacjach (Windows Phone, Windows 8). Możemy to zrobić w prosty sposób: dodać referencję w obu projektach do biblioteki PCL. Postaram się jednak pokazać na przykładzie jak dodawać ViewModele za pomocą prostego wzorca Inversion of Control, jakie daje nam biblioteka MVVMLight.

Na początek tworzymy sobie solucję, która zawierać będzie 3 projekty:

  • PCL – biblioteka  wspólna
  • PCL.WP8 – aplikacja Windows Phone
  • PCL.W8 – aplikacja Windows Store

W ostatnich dwóch projektach dodajemy referencję do pierwszego i od tej pory możemy zacząć dewelopować.

Części wspólne

Zacznijmy więc od projektu PCL. W poprzedniej części wkleiłem obrazek który pokazywał, że w tym rodzaju biblioteki powinniśmy przechowywać modele, viewmodele i interfejsy ujednolicające API Windows Store oraz Windows Phone. Dajmy na to, że chcemy w jednym z naszych ViewModeli zapisywać i odczytywać kontekst naszej aplikacji z pliku. Na Windows Phone plik taki będziemy przechowywać w IsolatedStorage, natomiast w aplikacji Windows Store, w Storage’u dla aplikacji. W takim razie możemy stworzyć sobie interfejs IDataSerializer, który zserializuje nam obiekt konkretnej klasy.

public interface IDataSerializer
{
    Task<ApplicationContext> LoadData();

    void SaveData(ApplicationContext context);
}

Ok, problem się zaczyna, kiedy chcemy w biblitece PCL rzeczywiście coś zapisać. Przecież nie możemy napisać var serializer = new IDataSerializer(). Potrzebujemy konkretnej implementacji. Do tego właśnie posłuży nam wzorzec Inversion Of Control. Wystarczy, że dodamy do wszystkich naszych projektów jakie stworzyliśmy do tej pory bibliotekę MVVM Light Libaries only (PCL). 


mvvmlightnuget

Uważajcie żeby nie dodawać innych bibliotek MVVM Light, bo potem mogą wyniknąć problemy z referencjami.

Następnie mając już dodane wszystkie referencje możemy pobrać konkretną instancję naszego interfejsu w taki oto sposób:

var dataSerializer = ServiceLocator.Current.GetInstance<IDataSerializer>();
var appContext = await dataSerializer.LoadData();

Na chwilę obecną nie interesuje nas czy to zapisuje do pamięci telefonu czy na dysk. Pobieramy konkretną implementację i ładujemy dane. Pierwsze pytanie, jakie się nasuwa to: “Ok, ale gdzie my to wstrzykujemy”. Właśnie, żeby wstrzyknąć konkretną implementację przechodzimy na początek do aplikacji Windows Phone i wykonujemy następujące kroki:

  1. Tworzymy klasę ViewModelLocator
  2. Dodajemy statyczny konstruktor dla tej klasy i w środku wstrzykujemy naszą własną implementację zdefiniowanego wcześniej interfejsu (1):
    static ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        SimpleIoc.Default.Register<IDataSerializer, WPDataSerializer>();  //1
    }
  3. W pliku App.xaml dodajemy do Application Resources definicję naszej klasy, aby przy starcie aplikacji wykonał się nam konstruktor:
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator" />
    </Application.Resources>

Identyczne kroki powtarzamy dla aplikacji Windows Store, przy czym podajemy mu inną implementację naszego interfejsu.

Po wykonaniu tych 3 kroków wszystko jest już gotowe. Jeśli uruchomimy aplikacje Windows Phone, to logika w PCLu skorzysta z WPDataSerializer, natomiast jeśli uruchomimy aplikację Windows Store, ServiceLocator zwróci nam obiekt W8DataSerializer (czy jak tam go sobie nazwiemy).

ViewModele

Tutaj praktycznie kończy się nasza wiedza potrzebna do zaimplementowania PCL-a. Natomiast chciałbym również pokazać jak MVVM Light pozwala na wstrzykiwanie ViewModeli do widoków. Czasami chcemy aby dla jednej strony powstała tylko jedna instancja ViewModel i za każdym wejściem na tę stronę otwierał się ten sam obiekt, a nie nowy. Ja wcześniej to załatwiałem poprzez tworzenie statycznej właściwości w App.xaml.cs i pobierania ViewModelu stamtąd. Natomiast mając już zaimplementowane IoC możemy to zrobić w trochę inny sposób. Sposób ten działa zarówno dla WP jak i W8:

  1. W naszym pliku ViewModelLocator dodajemy (1 – jeśli chcemy stworzyć jedną instancję ViewModelu, 2 – jeśli chcemy tworzyć zawsze nową instancję)
    //1
    public HomeViewModel Home
    {
        get
        {
            return ServiceLocator.Current.GetInstance<HomeViewModel>();
        }
    }
    
    //2
    public HomeViewModel Home
    {
        get
        {
            return new HomeViewModel();
        }
    }
  2. W widoku dodajemy do głównego elementu (PhoneApplicationPage – WP, Page – W8) taki atrybut:
    DataContext="{Binding Home, Source={StaticResource Locator}}"

PS. Zacząłem tworzyć bibliotekę wystawiającą interfejsy dla podobnych części systemu Windows Phone oraz Windows 8, natomiast podczas jej pisania zauważyłem, że oba te system tak bardzo się jeszcze różnią, że nie potrafię wielu rzeczy połączyć w jeden interfejs. Możliwe, że niedługo dopiszę brakujące rzeczy i wtedy wrzucę ją na github’a.

PS2. Mam w planach nakręcić filmik pokazujący w trochę bardziej praktyczny sposób połączenie ze sobą tych dwóch aplikacji, natomiast brak czasu i brak pomysłu na taki filmik trochę mnie zatrzymuje.

Co twój język programowania o tobie mówi?

Już trochę czasu siedzę w świecie programistów i zdążyłem zauważyć pewne wzorce, to, że decyzja o wyborze języka w jakim się specjalizujesz, często wpływa na to z kim się zadajesz, a to bezpośrednio wpływa na to jaki masz charakter. Poniższy tekst jest oczywiście przebarwiony, dlatego jeśli bardzo mocno utożsamiasz się ze swoim językiem programowania nie czytaj tego.

1. Entuzjaści Open Source (Ruby)

Kiedy pytasz się ich jakiego IDE używają to patrzą na Ciebie dziwnym wzrokiem, jakby pierwszy raz słyszeli takie słowo. Do pełni szczęścia potrzebny jest im tylko dobrze skonfigurowany VIM. Z racji tego, że nie ogranicza ich system operacyjny, gdyż VIM jest dostępny na każdy system, najczęściej siedzą na iOSie albo Ubuntu. Często swoją pracę wrzucają na github-a i nierzadko biorą udział w jakichś projektach opensource-owych. Przez to, że programują nawet po pracy to mają raczej mało czasu dla rodziny i znajomych.

2. Freelanserzy (JavaScript)

Ludzie, którzy kiedyś byli zmuszeni przez szefa do użycia javascriptu w kilku projektach przez co wyżywali się pewnie na wszystkich w około. Od chwili jednak kiedy javascript stał się modny już nie narzekają (albo nie mówią tego głośno), a wychwalają brak ograniczeń w JSie.

Prawdopodobnie jedyne projekty które mają logikę w javascripcie to przykłady z których się uczą albo mały projekt dla niewielkiej sieci pizzerii. Większość programistów tworzących w javascripcie to jednak frontendowcy.

3. Apple Fanboys (objective-c)

Apple wszystko robi na przekór innym, dlatego język programowania w jakim pisane są ich aplikacje też musiał być zrobiony inaczej. Osoby, które programują w tym języku nie ruszają się nigdzie bez swojego służbowego IPhone, IPada czy MacBooka. W końcu co 5 min trzeba wrzucać info na twittera, 4square i jakieś zdjęcie na instagrama. Podświadomie mają też coś z masochistów, bo jak bardzo trzeba kochać markę, żeby zgodzić się na programowanie w języku w którym składnia jest tak bardzo powalona.

4. Korporacyjne sprzedawczyki (C#)

Uzależnienie od Microsoftu zaczyna się już w czasach studiów, kiedy to przyszli pracownicy dostają za darmo wszystko co dusza zapragnie (Visual Studio, Windows Server, SQL Servery). Darmowe wersje są idealne do małych projektów na studia. Kiedy jednak już opuszczają mury akademii są tak uzależnieni od technologii Microsoftu, że jedynym miejscem gdzie mogą nasycić swój głód są duże korporacje, które stać na zakup licencji.

Dlatego zatrudniają się w takich firmach przymykając oko nawet na to, że od czasu do czasu ktoś każe im założyć krawat. Po kilku latach spędzonych w korporacji coraz mniej programują a coraz częściej noszą krawat, aż przestają programować i nie wiedzieć kiedy budzą się jako managerowie, albo team leaderzy.

5. Jedyni prawdziwi programiści (Java)

Uważają się za jedynych prawdziwych programistów, akceptują jedynie jeszcze programistów C++. Najchętniej używają produktów, które można konfigurować edytując dane w pliku. Zwykłe checkboksy i przełączniki są zbyt ograniczające. Ponieważ uwielbiają konfigurować wszystko pod siebie nie rozumieją często użytkowników końcowych i sami od siebie dodają milion możliwości konfiguracji swoich produktów.

Większość z nich uważa Microsoft za centrum zła, dlatego kompilują 3 razy w miesiącu swoje Gentoo, tylko dlatego żeby pośmiać się na forach z lamerów używających Windowsy albo Ubuntu. Ach i cały czas pamiętają, że Microsoft okradł ich tworząc C#.

6. Hakerzy (C++)

Niewielu nowych programistów wybiera  C++, przede wszystkim dlatego, że aby napisać w nim jakiś program trzeba napisać średnio 3 razy więcej kodu niż w językach wyższego poziomu. Dla tych którzy jednak wytrwają czeka nagroda. Mogą zaliczyć się do grona prawdziwych hakerów i wyśmiewać się z tych wysokopoziomowych lamerów.  Jedyni programiści jakich akceptują to programiści C i assemblera.

Jako, że napisanie programu w C++ zajmuje również więcej czasu, firmy używają go głównie w aplikacjach, które muszą wykorzystywać specyficzne właściwości sprzętu bądź systemu. Dlatego pasja do C++ często łączy się z pasją do elektroniki i czytaniem 1000 stronicowych manuali.

7. Naukowcy (MATLAB, Clojure)

Przeważnie są to osoby, które bardziej niż programowaniem pasjonują się matematyką, a komputery uważają jedynie za duże konfigurowalne kalkulatory. Najczęściej siedzą na uczelni i piszą kolejne książki o tym jak w nowatorski sposób obliczyć transformatę furiera. Niestety ponieważ zostają na uczelni, studenci informatyki również muszą dowiedzieć się tego jak obliczać problemy matematyczne za pomocą komputera, mimo, że późniejsza praca polega jedynie na stosowaniu wzorców i nigdzie poza uczelnią nie rozwiązuje się problemów matematycznych większych niż odejmowanie od siebie dwóch dat.

Zdaje sobie sprawę z tego, że opis tych grup jest czysto subiektywny i wynika z moich spostrzeżeń w kontaktach z innymi programistami. Niemniej miałem niezłą frajdę pisząc ten artykuł :)

Portable Class Library, czyli tworzenie logiki współdzielonej cz.1

Ostatnio zauważyłem, że produkty Microsoftu skierowane dla programistów stają się coraz przyjemniejsze i coraz bardziej zautomatyzowane. Microsoft stara się jak może, żeby umilić nam codzienne zmagania w pracy. Jednym z takich produktów, o których nie wiele osób piszących aplikacje mobilne pod systemy Microsotfu (Windows Phone i Windows 8) wie jest Portable Class Library. Co to jest i co można w nim zrobić? Postaram się opisać w tym oraz w kolejnych postach dotyczących właśnie PCL-a.

Od wielu programistów Androida słyszę zarzuty, że pisanie pod Androida jest lepsze, bo robią jedną aplikację i działa ona zarówno na tabletach i smartfonach. Wtedy zazwyczaj się uśmiecham i odpowiadam, że dla mnie to największy minus Androida. :) Całe szczęście Microsoft nie poszedł w tą samą stronę, lecz pomyślał trochę i zaprezentował nam, już razem z Visual Studio 2012 bibliotekę, która może być dołączana zarówno do aplikacji Windows Phone jak i Windows Store.

pcl-createproject

Ok, trochę oszukałem… może być dołączana nie tylko do mobilnych aplikacji, ale również do aplikacji Silverlight-owych oraz zwykłych aplikacji pisanych pod .NET Framework. A nawet, za pomocą Xamarin, aplikacji Android-owych oraz IOs-owych.

PCL-Dialog

Oczywiście biblioteka działa na częściach wspólnych, więc im więcej projektów wybierzemy, tym mamy mniej możliwości do wykorzystania. Należy się więc zastanowić co chcemy umieścić jako części wspólne. Może to być oczywiście połączenie do bazy danych, nie będziemy musieli pisać 2 razy tych samych DAO, helpery działające bez specyficznych operacji dla systemu, bądź ViewModele jeśli posiadamy identyczne dla obu systemów. Dodatkowo można wydzielić interfejsy w przypadku gdy oba systemy posiadają podobną funkcjonalność, ale sama implementacja wygląda inaczej. Przykładem takiego interfejsu może być robienie zdjęć. Zarówno w Windwos 8 jak i Windows Phone 8 istnieje możliwość pobrania zdjęć z aparatu (bądź kamerki). W obu systemach jednak implementuje się to inaczej. common-architectureAktualnie właśnie zacząłem pisanie takiej biblioteki, która zawierałaby wszystkie części wspólne tych systemów i wystawiała interfejs dla PCL’a. Nie wiem ile zajmie mi napisanie implementacji 9 interfejsów, jakie do tej pory znalazłem więc nie podaje daty kiedy kod pojawi się na githubie ;)

Post ten miał na celu opisanie tego czym jest PCL i zachęcenie do używania go, nawet jeśli nie mamy w planach (na razie) robienie aplikacji na inny system. W kolejnym poście postaram się pokazać jak zaimplementować wzorzec MVVM używając PCL i MVVMLight.

Bardziej przyjazny pulpit.

Pisałem już wcześniej jaki sprzęt przyjde się w pracy programisty. Chyba każdy się jednak zgodzi, że dobry sprzęt nie wystarczy, jesli nie mamy odpowiednio skonigurowanego środowiska, można mieć 8GB ramu to jednak nie pomoże jeśli będziemy programowac w notatniku. Dzisiaj chciałbym podzielić się z wami kilkoma programami, które umilają pracę z Windowsem (poniekąd upadabniając go trochę do dystrybucji linuksa ;) ).

VirutalWin

Każdy kto pracował na którejś z dystrybucji linuksa na pewno zna feature wielu ekranów. Za czasów ubuntu 7.x kiedy to istniał jeszcze Beryl (dla tych, którzy nie pamiętają) robienie kostki z ekranów było pierwszą rzeczą na zaraz zainstalowanym systemie. Niewątpliwie jednak nie jest to potrzebne tylko żeby ładnie wyglądało, ale na pewno też zwiększa produktywność. Nie mając dwóch monitorów możemy sobie podzielic programy na grupy i trzymać je na oddzielnych pulpitach. Jest to bardziej przydatne niż przełączanie 4 programów za pomocą alt + tab. Aktualnie używam VirtualWin z dwoma zewnętrznymi monitorami, więc mam aż 8 pulpitów.

PS. Niestety VirtualWin nie umożliwia takich ładnych przejśc między pulpitami jak w linuksie.

F.Lux

Kolejnym programem, który instaluje zaraz po instalacji windowsa jest f.lux. Chociaż na codzień nie odczuwa się tego, że ten program działa, to na pewno odczuje sie jeśli wyłączymy go późnym wieczorem. F.lux zarząca jasnoscią oraz temperaturą ekranu w zależności od pory dnia. O ile rano zimne odcienie na ekranie nie przeszkadzają w codziennej pracy, to wieczorem ekran może nieźle zmęczyć oczy. F.lux podgrzewa nam trochę kolory na monitorze, robi to prawie niewidocznie a pozwala to na siedzenie późnymi wieczorami przed monitorem bez efektu zmęczonych oczu.

Fences

Wiele osób uważa, że najlepszym miejscem na przechowywanie dokumentów jest pulpit. Sam często zapisuje coś na pulpicie, który bo potrzebne jest mi to tylko na chwilkę, po czym okazuje się to całkiem przydatne i tak zostaje. Nim się obejrzymy nasz pulpit może zamienić się w straszny syf.

Fences to aplikacja, która pozwala pogrupować pliki na pulpicie oraz schować je jeśli nie są nam aktualnie potrzebne. Dwukrotne kliknięcie na pulpicie chowa lub pokazuje nasze ikony.

Sublime Text

Wiele razy szukałem odpowiedniego edytora tekstu dla programisty. Przez większość czasu używam Visual Studio, jednak są takie pliki, dla których nie chce odpalać specjalnie VS’a, chociażby pliki sql. Chciałbym jednak aby edytor tekstu podświetlał składnie oraz umożliwiał szybką edycję takich plików. Przetestowałem już wiele edytorów: Notepad++,Notepad2GVim, w końcu trafiłem na Sublime Text i przy nim chyba na razie zostanę. Sublime w wersji darmowej zawiera podstawowe funkcjonalności, można również kupić licencje i korzystać z dodatkowych feauterów. :)

Chocolatey

O apt-get pod windowsa było głośno jakiś czas temu, ostatnio trochę słuch o tym zanikł, a szkoda, bo jest to bardzo przydatne narzędzie zwłaszcza dla osób, które często reinstalują system. Nie powiem, że jest to odpowiednik debianowego apt’a, bo liczba programów nadal jest dosyć skromna w porównaniu z repozytorium debiana. Niemniej jednak możemy znaleźć ponad 1200 programów, w tym najniezbędniejsze do programowania (git, 7zip, node.js,  i wiele innych). Dzięki temu możemy w prosty sposób stworzyć skrypt, który instaluje chocolatey a następnie za jego pomocą dociąga nam najnowsze wersje programów i instaluje nam je.

Przedstawiłem tylko kilka przydatnych narzędzi, wiem że jest ich o wiele więcej, jeśli więc używacie jakiegoś programu, bez którego nie wyobrażacie sobie życia, to dajcie znać w komentarzu, chętnie przetestuje :)

Pierwsze zabawy z MongoDb

Już od dłuższego czas chciałem poznać jedną z baz NoSql-owych. Niestety zawsze jak się zabierałem za poznawanie jakiejś miałem nad głową termin skończenia projektu i wolałem zrobić coś szybko w znanych mi już relacyjnych bazach danych. Teraz zacząłem projekt, którego zakończenie przewiduje na marzec, więc mam jeszcze trochę czasu żeby pobawić się czymś nowy. Jedną z nowości, które zamierzam lepiej poznać to darmowa, NoSql-owa baza danych MongoDB. Jest to baza dokumentowa, więc wszystkie dane przechowuje w postaci plików json. Podejście to projektowania danych jest trochę inne niż w bazach takich jak MS SQL Server, ponieważ nie ma tutaj relacji. Oczywiście można sobie zamodelować przechowywanie kluczy, ale lepiej jest trzymać wszystko w jednym dokumencie.

Czego potrzebujemy żeby zacząć przygodę z MongoDB?

Przede wszystkim musimy pobrać bazę ze storny producenta (http://www.mongodb.org/downloads). Następnie rozpakowujemy pobrane archiwum i właściwie już możemy odpalić bazę. Aby to zrobić uruchamiamy konsole (cmd/powershell), wchodzimy do katalogu bin i piszemy:

.mongod.exe -dbpath sciezka_do_katalogu_z_danymi

Nie zamykamy konsoli, gdyż spowoduje to zamknięcie bazy. Domyślnie nasza baza zostanie uruchomiona na 127.0.0.1:27017. Niestety nie możemy uruchomić żadnego panelu admina ani nic co pomoże nam zarządzać bazą poprzez przeglądarkę. Do tych celów polecam program Robomongo. Dzięki niemu będziemy mogli podejrzeć dane, dodać, aktualizować czy wywoływać własne skrypty.

 

Czas połączyć to z .NET-em

MongoDB świetnie integruje się z .NET-em. Cała dokumentacja jak zrobić bardziej zaawansowane rzeczy znajdziecie na stronie http://docs.mongodb.org/ecosystem/drivers/csharp/ Przede wszystkim warto przeczytać CSharp Driver LINQ Tutorial, żeby zobaczyć jak używać LINQ do wyciągania danych z bazy.

Do używania mongo potrzebne są dwie biblioteki: MongoDB.Bson.dll oraz MongoDB.Driver.dll, obie można zainstalować poprzez Package Manager z lini poleceń:

PM> Install-Package mongocsharpdriver

lub poprzez wizualny manager NuGet’a (Official MongoDB C# Driver). Tyle wystarczy żeby móc już używać mongoDB w swoim projekcie.

Jako bonus dołączam moją implementację wzorca Repository skierowanego specjalnie dla MongoDB. Klasa ta posiada, kilka moich zdaniem kluczowych funkcjonalności takich jak:

  • zwraca nie cała listę obiektów, a obiekt IQueryable, który pozwala na tworzenie kwerend LINQ,
  • zwraca obiekt po jego Id,
  • przy dodawaniu nowego obiektu generuje mu nowe Id,
  • jeśli nie podamy nazwy kolekcji stworzy automatycznie kolekcje odpowiadającą nazwie typu obiektu, który zapisujemy w bazie.
/// <summary>
/// This class provides Id property
/// </summary>
public abstract class ModelBase
{
    public string Id { get; set; }
}

public class MongoRepository<T> 
    where T : ModelBase
{
    public MongoDatabase Database { get; private set; }

    private string _tableName;

    public MongoRepository(string tableName)
    {
        this._tableName = tableName;
        CreateDatabase();
    }

    public MongoRepository()
    {
        CreateDatabase();
    }

    private void CreateDatabase()
    {
        MongoClient client = new MongoClient();
        MongoServer server = client.GetServer();
        Database = server.GetDatabase("databasename");
    }

    public IQueryable<T> GetAll()
    {
        var col = GetTColection();
        return col.AsQueryable<T>();
    }

    public T GetById(string id)
    {
        var col = GetTColection();
        return col.AsQueryable<T>().Single(e => e.Id == id);
    }

    public void Add(T obj)
    {
        if (obj.Id == null )
        {
            obj.Id = ObjectId.GenerateNewId().ToString();
        }
        var col = GetTColection();
        col.Insert(obj);
    }

    public void Remove(string id)
    {
        var col = GetTColection();
        col.Remove(Query.EQ("_id", id));
    }

    public void Update(T obj)
    {
        var col = GetTColection();
        col.Save(obj);
    }

    private MongoCollection<T> GetTColection()
    {
        if (!string.IsNullOrEmpty(_tableName))
            return Database.GetCollection<T>(_tableName);
        else
            return Database.GetCollection<T>(typeof(T).Name);
    }
}