Jak dostać pracę jako Junior Software Developer.

Zaczynasz swoją przygodę z programowaniem za pieniądze i szukasz firmy, która spełni Twoje oczekiwania, a jednocześnie chcesz wypaść jak najlepiej na rozmowie kwalifikacyjnej? Czytaj dalej a dowiesz się tego oraz wiele więcej.

Ostatnimi czasy rynek pracy dla programistów jest tak chłonny, że każdy znajdzie coś dla siebie. Niekiedy należy się jednak zastanowić, czy warto iść do pracy, w której biorą programistów „jak leci”, bez żadnego sprawdzenia ich umiejętności. Moim zdaniem, im trudniejsza rozmowa kwalifikacyjna, tym większa ochota na pracę. Jeśli firma dobrze sprawdza kompetencje kandydatów, to istnieje duża szansa, że będzie się pracować z najlepszymi. Ale jak pokazać, że należy się właśnie do nich?

1. Dowiedz się w jakich technologiach prowadzone są projekty.

Przede wszystkim należy dowiedzieć się, czego pracodawca wymaga od kandydata. Z ogłoszenia o pracę należy wyłapać technologie, z którymi pracują programiści w tej firmie. Najczęściej pracodawcy podają znajomości jakich technologii wymagają od kandydata oraz znajomość jakich będzie atutem. Wypisz sobie wszystkie jakie znalazłeś w ogłoszeniu. Może to być jakaś konkretna baza danych (MSSQL), framework (ASP.NET WebApi), czy biblioteki JavaScriptowe (Angular, React). Postaraj się przyswoić przynajmniej podstawy tych technologii. Włącz sobie jakiś tutorial i zapamiętaj co ważniejsze kwestie. Jeśli jakaś technologia znajduje się w ofercie pracy, to na rozmowie, na 90% o nią zapytają. Jeśli popiszesz się znajomością chociaż podstaw, ale ze wszystkich, to już znajdziesz się na uprzywilejowanej pozycji i będziesz postrzegany jako osoba pasująca do tej firmy.

2. Przypomnij sobie zagadnienia teoretyczne

Na rozmowie kwalifikacyjnej bardzo często pierwszym testem sprawdzającym kandydata są pytania teoretyczne.  Dlatego właśnie, przed taką rozmową należy przypomnieć sobie kilka książkowych kwestii. Takich jak:

Oczywiście istnieją też firmy, w których pytają Cię o to jak coś jest zrobione „pod spodem” czyli coś, co dla programisty nie jest widoczne gołym okiem. Przykładem takiego pytania jest: jak kompilator interpretuje sobie funkcje anonimowe (tak spotkałem się z takim), ale już bez przesady jeśli nie będziesz wiedział czegoś takiego, nikt Cię za to nie potępi.

3. Przygotuj sobie pytania od siebie

Na początku mojej kariery, najgorszy moment rozmowy był wtedy, gdy ktoś po przeciwnej stronie stołu zapytał się czy mam do niego jakieś pytania. Wiedziałem, że powinienem o coś zapytać, żeby pokazać, że zależy mi na konkretnym stanowisku, a nie dlatego, że przyszedłem tam, bo ich oferta była najwyżej na stronie, ale nic nie przychodziło mi do głowy. Dopiero po jakimś czasie, ucząc się na błędach dowiedziałem się o co pytać, żeby nie wdepnąć w projekt, z którego szybko będziesz chciał uciec. A więc, o co pytać?

  • Zapytaj się o proces w jakim rozwijane są projekty. Jeśli odpowiedzą Ci, że pracują w Agile to poproś o wyjaśnienie jak dokładnie wygląda stosowanie tego w firmie. Czasami firmy mówią, że pracuje się u nich Agile-owo, bo to modne, ale nie są w stanie uzasadnić jak dokładnie to wygląda, wtedy powinna zapalić się pierwsza lampka ostrzegawcza, że coś w tej firmie jest nie tak.
  • Dowiedz się czy posiadają środowiska testowe, stageowe do testowania różnych wersji aplikacji. Środowisko deweloperskie, testowe dla testerów (stage) oraz produkcyjne to minimum jakie powinno być przy komercyjnych projektach. Jeśli programiści wrzucają poprawki kodu bezpośrednio na serwer produkcyjny bez jakiegokolwiek testowania to nie tak to powinno wyglądać.
  • Zapytaj się jak testują kod, czy programiści piszą testy jednostkowe, czy mają oddzielny zespół testerów. Jeśli w odpowiedzi dostaniesz „nasza aplikacja zbyt szybko się rozwija, żeby do niej pisać testy jednostkowe” lub „nasi klienci testują aplikacje na produkcji” to zastanów się zanim tam pójdziesz pracować.
  • Dowiedz się jak dbają o rozwój pracowników. Karta multisport i prywatna opieka zdrowotna to nie to o co mi chodzi. Jeśli pracujesz z konkretnymi technologiami to, żeby nie zawęzić sobie horyzontu co jakiś czas powinieneś rozwijać się w innych dziedzinach i poznawać inne technologie. Dlatego firma powinna Cię w tym wspierać i tak na przykład niektóre firmy finansują dostęp do pluralsight’a czy wyjazdy na konferencje.
  • Jeśli aplikacja, przy której będziesz pracować działa już produkcyjnie, dowiedz się jak jest z jej utrzymywaniem. Czy nie będzie tak, że przez pierwsze pół roku będziesz naprawiał bugi przy starej aplikacji, a nie napiszesz nic nowego. Najgorsze co może być to naprawianie nieswoich bugów.

Ponadto polecam 12 zasad lepszego kodu, które wymyślił i spisał Joel Spolsky, jeden z twórców StackOverflow. Polecam spisać sobie te pytania i pytać pracodawców o każdy punkt, im więcej punktów spełniają, tym lepiej jest u nich pracować.

4. Sprawdź czy ktoś z firmy nie mógłby Cię polecić.

W wielu firmach prężnie poszukujących programistów, działa system poleceń. Jeśli osoba z firmy poleci swojego znajomego, a ten dostanie pracę i utrzyma się 3 miesiące, to dostanie bonus pieniężny. Zastanów się więc, przejrzyj jeszcze raz znajomych na facebooku/linkedin czy w firmie, w której chcesz pracować nie ma żadnego Twojego znajomego. Jeśli jest, pogadaj z nim o tym jak pracuje się w jego firmie i poproś o przesłanie swojego CV do kogoś z działu HR. Twój znajomy na pewno chętnie to zrobi licząc na bonus pieniężny, a Ty nie będziesz kolejnym kandydatem z ulicy, a już kimś poleconym, więc wartym przesłuchania.

Mam nadzieję, że powyższe punkty pomogą Ci dostać wymarzoną pracę. Myślę, że w chwili obecnej jest tyle ofert dla programistów, że nie ma co brać pierwszej, która wpadnie Ci w ręce. Lepiej pójść na kilka rozmów, zobaczyć jakie są różnice pomiędzy ofertami i wybrać najodpowiedniejszą dla Ciebie. Jeśli miałeś jakieś ciekawe historie podczas rozmów rekrutacyjnych podziel się nimi w komentarzach 🙂

Typowe błędy programistów.

Pisałem już kiedyś o błędach popełnianych przez młodych programistów. Byłem wtedy na początku swojej programistycznej kariery i myślałem, że już dużo wiem. Teraz wiem ile jeszcze nie wiem 😉 Niemniej jednak z większością z tamtych punktów zgadzam się do dziś. Postanowiłem więc, po kilku latach jeszcze raz zebrać kilka najczęstszych błędów, które zauważyłem już w aplikacjach enterprise. Poniższe punkty nazwałem błędami architektonicznymi, czyli odnoszącymi się bezpośrednio do kodu programu. Jak wiadomo praca programisty składa się jeszcze z wielu innych aktywności, ale o nich napiszę w innym poście.

1. Nadużywanie statycznych metod

Statyczne metody nie powinny być zbyt często używane. Programiści często idą na skróty i dopisują funkcje statyczne, które zawierają logikę biznesową bądź zmieniają stan aplikacji. Logika biznesowa w metodach statycznych to najgorsze, co może być. Dlaczego? Dlatego, że dla takiej metody jest bardzo trudno napisać jakikolwiek test jednostkowy. Metody statyczne powinny być używane dla bardzo prostych helperów, służących tylko do prostych obliczeń, niewymagających testowania. Chodź i tak do tego lepiej nadają się extension methods. Przykład błędnego użycia metody statycznej znajdziecie poniżej.

var user = User.GetUserById(userId);

public class User
{
    public static User GetUserById(int userId)
    {
        //Implementation
    }
}

Zamiast tego powinno się używać serwisów, które mogą być wstrzyknięte poprzez DI i z łatwością zmockowane.

2. Niekorzystanie z interfejsów

Punkt ten często wiąże się z poprzednim, gdyż metod statycznych nie można umieścić w interfejsie. Często myślimy, że jeśli aktualnie do dostępu do bazy używamy ADO.NET, to tak będzie już zawsze i tworzymy metody pobierające/zapisujące dane w klasie, do której odwołujemy się bezpośrednio. Niestety takie podejście ma bardzo wiele wad. Przede wszystkim, tak samo jak w przypadku metod statycznych bardzo ciężko jest testować taki kod. Nie można stworzyć żadnego mocka, który symulowałby nam dostęp do bazy danych. Drugim problemem z tym związanym jest brak możliwości zmiany aktualnie używanego rozwiązania. Jeśli już w całym programie używa się bezpośrednich połączeń do metod z ADO.NET, to nie przepiszemy wszystkiego na Entity Framework w jeden tydzień.

To co powinno się robić, to używać interfejsów zawsze. Nawet jeśli sposób implementacji w danym momencie jest tylko jeden.

3. Wrzucanie funkcji do jednego worka

Jeśli myślimy zbyt obiektowo, nadchodzi czas gdy biznes przerasta nasze obiektowe pojęcie. Wtedy właśnie zdajemy sobie sprawę, że nasza klasa User trochę się rozrosła i każda operacja mająca cokolwiek wspólnego z użytkownikiem, nie powinna znajdować się w tej jednej klasie. Często osoby, które nie stosują żadnych wzorców architektonicznych, popadają w pułapkę klas Bogów. Zamiast myśleć o obiektach jako encjach bazodanowych, należy pomyśleć o obiektach w kontekście biznesu. Bardzo przydatna w zrozumieniu tego zagadnienia jest książka Domain Driven Design. Pomocne w rozdzieleniu funkcji mogą być również wzorce projektowe, takie jak CQRS.

4. Wykorzystywanie tych samych DTO w wielu, niepowiązanych miejscach.

Najtrudniejsze w programowaniu jest wymyślanie nazw. Dlatego często idziemy na łatwiznę i nadajemy nic nie znaczące nazwy. Załóżmy, że mamy klasę do edycji użytkownika, więc nazwiemy ją UserDto. Po kilku miesiącach zapominamy, piszemy inną funkcjonalność i dajmy na to, że musimy wyświetlić wszystkich użytkowników z daną rolą. Jakiej klasy użyjemy? Prawdopodobnie UserDto, pomijając, że klasa ta posiada znacznie więcej pól niż potrzeba przy prostym wyświetleniu użytkowników. Jest to kolejny błąd, który ciężko naprawić, bo im więcej odwołań do danej klasy tym ta klasa jest trudniej edytowalna.

5. Pisanie nieczytelnych funkcji

Temat pisania nieczytelnych funkcji, poruszany jest w wielu wątkach i opisywany w niejednej książce, mimo to myślę, że wciąż są problemy z czytelnym pisaniem funkcji. Przede wszystkim problemy występują w instrukcjach warunkowych, które potrafią być całkiem sporym kawałkiem logiki. Istnieje nawet kampania anty-ifowa, której członkowie namawiają do programowania bez użycia instrukcji if oraz switch. Nie jestem za popadaniem ze skrajności w skrajność i wiem, że czasami użycie if jest czytelniejsze niż przerobienie architektury, niemniej jednak należy zwrócić uwagę na to, czy inni programiści zrozumieją, kiedy kod wchodzi do bloku if.

Poniższy przykład pokazuje świetnie ewolucje oprogramowania. Pierwsza linijka jest akceptowalna, bo to tylko jeden warunek, do tego w miarę czytelny i logiczny- ma pieniądze, więc może kupić. Po dodaniu funkcjonalności ról, umieszczamy kolejny warunek i już zaczyna się robić mało czytelnie. W tym momencie powinniśmy opakować cały warunek w jakąś ładnie brzmiącą metodę. Niestety wiele razy widziałem, że ostatni krok jest pomijany i zostaje taki tasiemiec z instrukcji warunkowych, nad którym trzeba spędzić kilka minut, żeby go zrozumieć.

// this is readable
if (user.AccountBalance >= productCost) { }

// we add Roles to program and code is ugly
if (user.AccountBalance >= productCost && user.Roles.Any(r => r.AllowInAppPurchases)) { }

// after refactor it is better
if (user.CanBuyProduct(productCost)) { }

To tylko kilka uwag, które zamierzałem przedstawić, żeby przestrzec innych. Często w pośpiechu sam zapominam o niektórych zasadach, ale mam nadzieję, że dzięki opisaniu ich tutaj, sam zacznę się bardziej pilnować. 🙂

Czemu używać git-a nawet jeśli nie potrzebujesz zdalnego repozytorium?

Jestem przekonany, że wielu z was (programistów) posiada swoje własne projekty, rozwijane „po pracy”. Proces, w jakim nad nimi pracujecie jest prawdopodobnie zupełnie inny, niż ten wyuczony w pracy. Jeśli byłby taki sam, to nie byłoby frajdy z rozwijania czegoś własnego, prawda? Mimo, że istnieje wiele darmowych systemów (bitbucket, visualstudio) pozwalających na założenie swojego własnego systemu kontroli wersji i przechowywania swojej aplikacji w chmurze, to nie zawsze wydaje się warte zaśmiecanie internetu swoimi małymi projekcikami, a prawdopodobieństwo, że padnie nam dysk jest raczej niewielkie. Wtedy większość osób po prostu umieszcza swoją aplikację w folderze i pracuje nad nią, czasami nawet tygodniami. Zdarzają się czasami nawet chwile, że dodając nową funkcjonalność zapędzamy się na tyle w programowaniu, że czasami chcielibyśmy wrócić do wcześniejszej wersji, ale cóż, przecież Windows nie wersjonuje plików. Otóż dla tych, którzy spotkali się z taką sytuacją, mam wskazówkę, jak nie powtórzyć tego błędu w przyszłości. Tą wskazówką jest jedna komenda odpalona w wierszu poleceń.

git init

8 znaków (licząc spacje) i tworzymy własne repozytorium. Nie potrzebujemy konta, ani połączenia z internetem. Jedyne, co potrzebujemy to zainstalowany git na naszym komputerze. Dla Windowsa możecie go pobrać ze strony git-scm. Przed pierwszym commitem polecam dodać plik .gitignore, który wykluczy z repozytorium niepotrzebne pliki takie jak pliki exe, czy dll. Możecie pobrać już wygenerowany plik pod swoje własne środowisko na stronie gitignore.io. Po dodaniu tego pliku wpisujemy komendę:

git add .
git commit -a -m "this is init commit"

Możemy się już cieszyć swoim własnym prywatnym repozytorium. Więcej informacji, co możecie zrobić z takim repozytorium znajdziecie w darmowej książce Pro Git.

Podglądanie historii commitów za pomocą git log

Dodam tylko, że jeśli w pewnym momencie będziecie chcieli swoje prywatne repozytorium wrzucić na githuba lub inny serwer i podzielić się ze znajomymi, nie ma nic prostszego.

git remote add origin 'remote-repository-URL'
git remote -v
git push origin master

Pozdrawiam i życzę miłego korzystania z gita 🙂

Szybki sposób na Dependency Injection w ASP.NET WebAPI

Konfiguracja pakietu DI, takiego jak Ninject zawsze kojarzyła mi się z wieloma problemami, żmudną konfiguracją i tworzeniem DependencyResolvera. Tak było dopóki nie odkryłem wspaniałej paczki nugetowej, która załatwia wszystko za developera. Wystarczy zainstalować paczkę Ninject.WebApi.DependencyResolver.

Install-Package Ninject.WebApi.DependencyResolver

Paczka ta dociągnie wszystkie zależności w tym paczki Ninject-owe. Przed odpaleniem projektu należy jeszcze otworzyć plik: App_Start/NinjectWebCommon.cs i w metodzie CreateKernel(), tuż przed return dodać wpis:

System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.WebApi.DependencyResolver.NinjectDependencyResolver(kernel);

Zastanawiacie się co dalej? To wszystko, możecie już korzystać z wstrzykiwania zależności, poprzez konstruktor bądź poprzez atrybut Inject. Więcej o bibliotece Ninject znajdziecie tutaj.

TIP: Nie wiem czemu, ale ja po instalacji jeszcze błąd, że nie można znaleźć biblioteki Ninject.dll w wersji 3.2.0.0. Spojrzałem i rzeczywiście zainstalowała się wersja 3.0.0.0. Dlatego musiałem jeszcze zaktualizować tą bibliotekę:

Update-Package Ninject

Po tym już wszystko działało poprawnie.

Internet mobilny z Play na OS X El Capitan

Ostatnio zmagałem się z konfiguracją internetu mobilnego w play. Trochę nad tym posiedziałem, więc chciałbym opisać rozwiązanie problemu, który może przytrafi się też komuś innemu. Otóż zakupiłem w salonie play model Huawei E3372h wraz ze starterem. Niestety nie doczytałem, że model ten wspiera systemy Mac OS X w wersji: 10.7, 10.8 i 10.9. Aplikacja play dołączona do modemu nie potrafiła sobie poradzić z El Capitan (10.11) i wyrzucała błąd:

The installer could not install the software because there was no software found to install. 

play_installation_failed

Przeczytałem kilka wpisów i nic nie pomagało, dopiero po jakimś czasie wpadłem na genialny pomysł aby wejść na stronę Huawei i sprawdzić sterowniki do tego modemu. Strona nie jest zbyt intuicyjna, ale udało się odnaleźć odpowiednią zakładkę. Po wejściu kilkamy link Update i dostajemy firmawre dla wszystkich wspieranych systemów. W moim przypadku pobrałem plik Stick Mobile Partner(for MAC10.11). Po instalacji tego programu, podpinamy nasz modem i program sam powinien wykryć konfiguracje i pozwolić na połączenie do internetu.

Fixing linq typings to work with es6

I’m sure that everyone knows linq. It is library which is very useful and has version not only in C# but also in JavaScript. Using linq in javascript may be useless few years ago but now it’s common problem that we need do some buisiness logic operations in js. I worked on few projects where i used Linq in javascript but lately i wanted to use it in Aurelia which is using es6 (ecmascript 6). First i had a problem how to use npm library in Aurelia which use jspm. I asked about that in stackoverflow and get the answer. But then i started using typescript and everything f**ed up.

First i needed typings for linq, so i googled linq.d.ts and get first answer. I added this to my project and created first typescript class. What happened? Visual studio shows error that cannot find module ‚linq’.

I thought that this is something with npm package. But when i wrote the same import in javascript it worked fine. So i checked linq.d.ts file and tried to changed it to meet the import statement. I didn’t changed any interfaces to be sure that i will have correct typings, but what i changed was module declaration. Original module declaration was:

declare module linq

I changed that to:

declare module 'linq'

Error about module disappear but i got another error.

So i had to move Enumerable variable into module declaration and make this variable default export.

declare module 'linq' {
    
    //Interfaces...

    var Enumerable: EnumerableStatic;
    export default Enumerable;
}

That helped, there is no error anymore. It should work for most of you, but because of my clumsiness i didn’t noticed that linq in some version changed their functions names. In some older version it was PascalCase (with first letter is capital ex. SingleOrDefault()) and now it is the same as all javascript functions so camelCase (ex. singleOrDefault()). So again i had to change my typings. I found the newest one at linqjs codeplex page. Did the same changes (with module name and default export) again and now i can use linq in typescript with ecmascript 6 features.

If anyone interested here you can download linq.d.ts file.

Windows Store Apps – Typescript

Dzisiaj chciałbym przedstawić swój pierwszy videotutorial, w którym kontynuuje tematykę Windows Store Apps pisanych w HTML5 i JavaScript. Myślałem już jakiś czas temu, aby zamiast pisania artykułów nakręcić film, na którym można dużo więcej pokazać i w końcu mi się udało. Myślę, że jest to lepsza forma przekazywania wiedzy i liczba błędów, które można popełnić odtwarzając kroki jest również o wiele mniejsza. Zachęcam do obejrzenia i komentowania 🙂

Kod źródłowy projektu po modyfikacji znajdziecie tutaj.

MVVM dla aplikacji Windows Store pisanych w JavaScript

Sporo się mówi/pisze o zastosowaniu wzorca MVVM w aplikacjach Windows Store i Windows Phone (teraz to chyba jest pod jedną nazwą ;)). Istnieje kilka bibliotek, jak na przykład MVVMLight, które pomagają w implementacji tego wzorca w XAML-u i C#. Niewiele się jednak mówi o aplikacjach Windows Store pisanych w języku JavaScript. Wydaje mi się, że niewiele osób kiedykolwiek próbowało stworzyć aplikacje dla Windows Phone w tym języku. W zasadzie to się nie dziwię, JavaScript to dziwny język i można go kochać lub nienawidzić. Niemniej jednak chciałbym pokazać, że pisanie aplikacji Windows Store w JS nie jest takie złe a w tym poście przede wszystkim chciałbym pokazać, że zastosowanie wzorca MVVM jest możliwe i jest bardzo proste.

1. Zacznijmy od stworzenia nowego projektu, polecam przy tworzeniu wybrać Navigation App, ponieważ stworzy nam się prawie pusta aplikacja, ale ze wszystkimi potrzebnymi rzeczami. Jeśli zaczęlibyśmy od Blank App, musielibyśmy posiedzieć jeszcze trochę nad poukładaniem stron, tak, aby można było zacząć programować.

winjs1

2. Język XAML jest wręcz stworzony do stosowania wzorca MVVM, wbudowany w ten język mechanizm bindingu pozwala nam stosować MVVM bez potrzeby dodawania jakiekolwiek zewnętrznej biblioteki. HTML niestety nie jest taki wspaniały, dlatego musimy wesprzeć się dodatkową biblioteką. Istnieje kilka bibliotek, których możemy użyć, ja natomiast najpewniej czuje się z biblioteką knokcoutjs, dlatego to w niej pokażę przykład. Bibliotekę tą możemy dodać za pomocą Nugeta, wyszukujemy knockoutjs i klikamy Install. Po tej operacji w katalogu Scripts powinny się nam pojawić dwa pliki knockout-{nr.wersji}.js i knockout-{nr.wersji}.debug.js.

winjs2

 

3. Otwieramy plik default.html i dodajemy link do pliku knockout-x.x.x.js, najlepiej przeciągając plik z solution explorera, w odpowiednie miejsce w dokumencie, ewentualnie wpisując ręcznie:

 <script src="Scripts/knockout-3.2.0.js"></script>

4. Tworzymy sobie nowy katalog o nazwie viewmodels. W tym katalogu będziemy przechowywać nasze klasy ViewModel. Dodajemy pierwszy plik js o nazwie MainViewModel.js. W środku, zaimplementujemy bardzo prostą logikę, wraz z dwoma polami do odczytu oraz metodą wywołującą MessageBox.

var MainViewModel = function (firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;

    this.sayHello = function () {
        var msg = new Windows.UI.Popups.MessageDialog("Hi! my name is " + this.firstName + " " + this.lastName);
        msg.showAsync();
    }
}

5. Przechodzimy do pliku home.html, i w miejsce „Content goes here” wklejamy prosty binding imienia i nazwiska oraz binding funkcji sayHello.

Imie:  
Nazwisko:

6. Zostajemy jeszcze w tym samym pliku i w znaczniku head, dodajemy odwołanie do naszego skryptu z MainViewModel, tak samo jak w punkcie 3 przeciągając plik MainViewModel.js w odpowiednie miejsce.
7. Zostaje nam na sam koniec tylko stworzyć obiekt viewmodel i podbindować pod odpowiedni widok. Otwieramy więc plik home.js i w funkcji ready dodajemy dwie linijki:

var vm = new MainViewModel("Jan", "Kowalski");
ko.applyBindings(vm);

8. Efekt, jaki powinniśmy dostać to aplikacja wyświetlająca Jan Kowalski oraz przycisk, po naciśnięciu którego powinien pojawić się MessageBox.

winjs3

 

Jeśli ktoś wcześniej nie miał do czynienia z biblioteką Knockoutjs, to polecam stronę http://knockoutjs.com/ na której znajdziecie tutorial, dzięki któremu w bardzo szybki sposób można nauczyć się podstaw tej biblioteki. Oczywiście można tutaj stosować TwoWay binding, oraz wiele innych ciekawych rzeczy, które odkryjecie na pewno przechodząc tutorial.

Kod źródłowy do pobrania

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. 🙂