wtorek, 30 października 2012

Debugowanie usług windows w Visual Studio

Jak wiadomo debuger wielkim przyjacielem programisty jest, ale nie zawsze istnieje możliwość odpalenia go od tak sobie wciskając F5. W przypadku usług (serwisów) windows otrzymamy komunikat:
---------------------------
Błąd uruchomienia usługi systemu Windows
---------------------------
Nie można uruchomić usługi z wiersza polecenia lub z debugera.
Usługa systemu Windows musi być najpierw zainstalowana (przy użyciu pliku installutil.exe),
a następnie uruchomiona za pomocą Eksploratora serwera, 
Narzędzi administracyjnych usług systemu Windows lub polecenia NET START.
---------------------------
OK   
---------------------------
Pozostaje pytanie co z tym fantem zrobić? Jak na razie spotkałem się z kilkoma różnymi sposobami, np:
Nie są one jednak wygodne ponieważ w każdym przypadku wymuszają chwilowe dodawanie kodu, kompilację warunkową lub parametry lini komend sterujące przebiegiem uruchomienia serwisu. Jaki jest więc złoty środek? Otóż istnieje możliwość sprawdzenia czy uruchomiony proces umożliwia użytkownikowi interakcję. Służy do tego właściwość Environment.UserInteractive. Dzięki niej wystarczy prosty warunek w punkcie wejścia do aplikacji aby rozdzielić przebieg raz a skutecznie. Czyli:
  • Zmieniamy rodzaj aplikacji na konsolową (wartość Output Type, zakładki Application, w Properties danego projektu) dzięki czemu zyskujemy wgląd w konsolę
  • Dodajemy kod umożliwiający odpalenie implementacji OnStart i OnStop przeciążonych po ServiceBase:
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
        }
    
        internal void Start(string[] args)
        {
            OnStart(args);
        }
    
        internal void Stop()
        {
            OnStop();
        }
    
        protected override void OnStart(string[] args)
        {
            //...
        }
    
        protected override void OnStop()
        {
            //...
        }
    }
    
  • Podmieniamy standardową metodę Main na:
    static void Main(string[] args)
    {
        Service1 svc = new Service1();
    
        if (Environment.UserInteractive)
        {
            Console.WriteLine("Starting...");
            svc.Start(args);
            Console.WriteLine("Started");
            Console.ReadLine();
            Console.WriteLine("Stopping...");
            svc.Stop();
            Console.WriteLine("Stopped");
        }
        else
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[] 
            { 
                svc
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
    
W ten sposób, kiedy wciśniemy F5 uruchomiony zostanie debugger z całym jego dobrodziejstwem. Natomiast po zainstalowaniu i uruchomieniu serwisu z poziomu services.msc odpali się druga klasyczna dla usług nitka kodu. Wilk syty i owca cała ;)

PS. Równie dobrze, zamiast konsoli można przygotować aplikację okienkową, nie ma tutaj ograniczeń, idea pozostaje niezmieniona.

wtorek, 7 czerwca 2011

Konsola zarządzania

Jakiś czas temu stwierdziłem, że w projektach jakie wykonuję brakuje mi takiego jednego centralnego czegoś... Konsoli w której szybko i bez problemu mógłbym wykonać przewidziane wcześniej zadania takie jak:

środa, 15 grudnia 2010

NHibernate 3 i QueryOver API

Całkiem niedawno pojawiła się nowa wersja NHibernate oznaczona numerem 3. Informacje co, gdzie i jak uległo zmianie można oczywiście znaleźć na głównej stronie projektu. Mi z tych wszystkich nowości najbardziej przypadło do gustu nowe API do wykonywania zapytań czyli QueryOver.

wtorek, 16 listopada 2010

Fluent Validation i dziedziczenie

FluentValidation jest całkiem przyjemną biblioteką, która jak wskazuje nazwa dostarcza narzędzie do walidacji klas poprzez interfejs typu fluent. Co czyni ją bardzo prostą w użyciu (przykłady w dokumentacji). Poza standardowym przypadkiem tzn mamy klasę, mamy walidator i gotowe, wspiera również zagnieżdżenia klas oraz walidację kolekcji. Do pewnego czasu wydawało mi się, że więcej do szczęścia nie będzie mi potrzebne. Zawsze jest jednak jakieś ale... Biblioteka ze względu na sposób budowania walidatorów (dziedziczenie po klasie AbstractValidator<T>) nie wspiera dziedziczenia ich samych, co jednak czasem może się przydać.

piątek, 29 października 2010

Operacje asynchroniczne, czyli C# 5.0

Każda kolejna wersja platformy .NET wprowadza coraz "fajniejsze" ułatwienia dla programisty. I chyba trudno się z tym stwierdzeniem nie zgodzić. Zaczęło się od anonimowych delegatów. Później bardziej funkcyjne podejście i LINQ. W .NET 4.0 wprowadzono słowo kluczowe dynamic. Teraz przyszedł czas na lepsze wsparcie dla operacji asynchronicznych. Od wczoraj dostępny jest do pobrania Visual Studio Async CTP, który do C# i VB wprowadza dwa nowe słowa kluczowe await oraz async.

środa, 20 października 2010

Debugowanie testów jednostkowych NUnit

Główną rolą testów jednostkowych jest wspomaganie wytwarzania oprogramowania poprzez testowanie element po elemencie (jednostce) całego rozwiązania. O ich zaletach nie trzeba się specjalnie rozwodzić ponieważ temat ten był i wciąż jest wałkowany na wielu blogach i serwisach tematycznych. Istotne jest, że po uruchomieniu testu wiemy co poszło nie tak, gdzie oraz jaki wynik powinniśmy otrzymać, a jaki otrzymaliśmy. W tym wszystkim zawsze brakowało mi jednak dokładnej wiedzy dlaczego coś poszło nie tak. Stąd możliwość debugowania testów jednostkowych wydaje się bardzo kusząca.

sobota, 21 sierpnia 2010

Problem PasswordBox przy wykorzystaniu wzorca MVVM

PasswordBox jak łatwo się domyślić jest standardową kontrolką WPF dzięki której użytkownik otrzymuje zamaskowane pole tekstowe do wpisywanie haseł itp. Kontrolka spisuje się wyśmienicie do czasu gdy przy budowaniu aplikacji nie wykorzystywany jest wzorzec MVVM (i inne pokrewne Model-View-* oparte o bindowaniu). Powód jest bardzo prosty. Ze względów bezpieczeństwa właściwość Password kontrolki nie jest uznawana jako Dependency Property co uniemożliwia bindowanie. Panowie z MS dokonali akurat takiego wyboru ponieważ wymusiłoby to ciągłe utrzymanie jawnego hasła w pamięci.