środa, 3 grudnia 2008

PG.NET XIV Spotkanie już dziś!

Zapraszam wsyzstkich na 14 sporkanie Poznańskiej Grupy .NET. Gościem specjalnym będzie Mariusz Jarzębowski, ktory opowie o histrii wstążki (The Storry of the Ribbon).

No a drugim gościem będe ja :-) Opowiem, jak podejść do tworzenia nowoczesnych aplikacji ASP .NET, czyli niezbędny toolbox: JavaScript, ASP .NET Ajax, itp.

Start: 17:45 w siedzibie firmy Cognifide

Rejestracja i agenda

sobota, 29 listopada 2008

Tip: Jak pobrać tytuł strony www. Niezawodnie.

Jest kilka sposobów na odczytywanie dokumentów tekstowych i wyszukiwanie w nich określonych treści. Często najbardziej niezawodne jest użycie do tego celu wyrażeń regularnych, czyli inaczej mówiąc regexa. Oto przykład jak pobrać tytuł witryny:

public string GetHTMLPageTitle(string file)
{
    Match m = Regex.Match(file, @"<title>\s*(.+?)\s*</title>");
    if (m.Success)
        return m.Groups[1].Value;
    else
        return string.Empty;    
}

Może się przydać :-)

piątek, 28 listopada 2008

Relacja po XIII spotkaniu PG.NET

Kto nie był, niech żałuje. Po pierwsze gratulacje dla zespołu Cognifide za pokaz ich (chyba sztandarowego) dzieła: EpiServera CMS. O ile byłem troszkę sceptycznie nastawiony do prezentacji, gdyż nie liczyłem na nic odkrywczego, to po prezentacji byłem zaskoczony na plus! Bardzo dobry przykład wykorzystania technologii .NET w stworzeniu naprawdę dużego narzędzia bijącego moim zdaniem Sharepointa na głowę. Kilka mechanizmów EpiServer mnie nawet zainspirowało - przedewszystkim ten rozszerzalny framework.

Inauguracja PLSSUG i prezentacja Stefana rozwiała przede wszystkim mój niedawny problem. Druga sprawa, to fajnie jest być na bieżąco jeśli chodzi o SQL Servera. Prezentacja również jak najbardziej udana. Stefan to niezły geek sqlowy :-). Taaak rozumiem jak to jest kiedy się przychodzi do domu, a tu nikt nie wie o czym się mówi :-)

Podsumowując: kolejny udany wieczór z kodem :-)

poniedziałek, 24 listopada 2008

PG.NET: XIII spotkanie już w czwartek


Na czwartek proszę, aby każdy poznański (ale mile widziana cała Polska!) developer .Net zaplanował sobie wieczór tak, aby móc wybrać się na spotkanie PG.NET
Na szczęśliwej, trzynastej odsłonie zaprezentowany zostanie projekt: EpiServer CMS firmy Cognifide (Adam Najmanowicz) oraz (uwaga) wystartuje PLSSUG (Polish SQL Server User Group) Poznań (Stef Konopnicki)!!
Agenda i rejestracja dostępna jak zwykle na stronie grupy: http://ms-groups.pl/pg.net/default.aspx
Obecność obowiązkowa!

IT Academic Days na Politechnice Poznańskiej

Mam przyjemność zaprosić wszystkich programistów i nie-programistów na imprezę Microsoft IT Academic Days, która odbędzie się 4 grudnia w Centrum Wykładowym Politechniki Poznańskiej. ITAD to cykl akademickich wykładów na których można zobaczyć i usłyszeć wiele ciekawych informacji o technologiach i innowacyjnych rozwiązaniach firmy Microsoft, ale nie tylko. Będę miał na niej swoje "pięć" minut przedstawiając wykład pt. "Trzej muszkieterowie, czli ASP .NET MVC". Start imprezy o godzinie 9:00. Dostępna jest już pełna Agenda. Zachęcam wszystkich gorąco, mimo że zimno :-) !

Wstęp jest bezpłatny, po wcześniejszej rejestracji na portalu CodeGuru. Strona konferencji: http://itacademicday2008.studentlive.pl/

poniedziałek, 17 listopada 2008

Data jest data?!

Operacje na datach to pewnie chleb powszedni dla każdego programisty. Wstawianie ich do bazy danych, to kolejna, seryjna nasza czynność. W zasadzie bardziej chodzi mi o umieszczanie domyślnych wartości daty w tabelach bazy danych MS SQL Server. W sumie niebyłoby nic odkrywczego, gdyby nie fakt, że wyjątki w takim kodzie pojawiają się w najmniej oczekiwanych momentach :-)

Istnieje spora różnica między wartościami: DateTime.MinValue, który w rezultacie da: 01-01-0001, a SqlDateTime.MinValue, który zwróci: 01-01-1753. Cała zabawa powoduję, że podczas próby wstawienia rekordu, którego wartość w kolumnie typu DateTime jest generowana w kodzie programu przez DateTime.MinValue otrzymujemy wyjątek przekroczenia wartości. Dlatego, aby wstawić minimalną wartość typu DateTime do bazy danych należy zawsze posługiwać się SqlDateTime.MinValue.

Jeszcze ciekawsza systuacja jest przy porównaniu wartości: DateTime.MaxValue oraz SqlDateTime.MaxValue. Zróbmy proste zadanie: wstawmy do tabeli w naszej bazie danych wartość DateTime.MaxValue, potem odczytajmy tą wartość do zmiennej lokalnej tego samego typu. Na szybko naskrobałem coś takiego:

static void Main(string[] args)
{
    DateTime fromDb = DateTime.MaxValue;
    DateTime toDb = DateTime.MaxValue;
    SqlConnection conn = new SqlConnection(@"Data Source=TOSHIBA\SQLEXPRESS;Initial Catalog=Poligon;Integrated Security=True");
    try
    {
        conn.Open();
        SqlCommand cmd = new SqlCommand("INSERT INTO Daty VALUES(@data)", conn);
        cmd.Parameters.Add("data", System.Data.SqlDbType.DateTime).Value = DateTime.MaxValue;
        cmd.ExecuteNonQuery();
        SqlCommand getCmd = new SqlCommand("SELECT TOP(1) DAT_Data FROM Daty", conn);
        using (IDataReader rdr = getCmd.ExecuteReader())
        {
            while(rdr.Read())
            {
                fromDb = Convert.ToDateTime(rdr["DAT_Data"]);
            }
        }
        bool areSame = (DateTime.Compare(toDb, fromDb) == 0);
        TimeSpan subDates = toDb.Subtract(fromDb);
        int result = subDates.Milliseconds; //nasz wynik
    }
    finally
    {
        conn.Close();
        conn.Dispose();
    }
}

Że co?


Metoda DateTime.Compare nie zwróciła nam wartości 0 (zero), co oznaczałoby, że data zapisana do bazy i ta odczytana są takie same. Zwróciła nam wartość, która oświadcza nam, że wartość otrzymana z bazy danych jest mniejsza od tej, którą zapisaliśmy.


Zaglądamy do zmiennej result...


Zmienna result trzyma dla nas różnicę obu dat. Po odjęciu wartości otrzymanej z bazy danych od tej którą zapisywaliśmy dostajemy różnicę wynoszącą... dwie równiutkie milisekundy.


Prawie robi wielką różnicę


DateTime.MaxValue to: 31-12-9999 23:59:59.999, natomiast maksymalna wartość daty dla bazy danych, czyli to co zwraca SqlDateTime.MaxValue to: 31-12-9999 23:59:59.997 Różnica dwóch milisekund występuje w momencie konwersji DateTime do SqlDateTime, tu nie otrzymujemy wyjątku - a powinniśmy gdyż zakresy nieznacznie, bo nieznacznie, ale różnią się. Baza danych posłusznie przyjmuje wartość potajemnie ucinając 2 ms. Biednemu developerowi wydaje się że wszystko jest ok (bo narzędzia podglądu danych oraz debugger nie wyświetlają wartości z tak dużą precyzją). Pytanie za 100 punktów: co powodują taką różnice? Dlaczego nie można było tej wartości wydłużyć o te 2 nieszczęsne milisekundy?

Inspektor Gadget, czyli śledzenie aplikacji cz. III

NLog - projekt o polskich korzeniach!

Tak, tak - nie tylko prezydent USA ma polskie korzenie! Ma je także NLog, gdyż został napisany przez polskiego programistę: Jarka Kowalewskiego. Ale nie dlatego chcę przedstawić tą bibliotekę jako wartą wypróbowania. Jest to biblioteka, która z pewnością dostarczy nam wszystkich niezbędnych mechanizmów potrzebnych do logowania zdarzeń w naszych aplikacjach. Niestety aktualnie autor nie uczestniczy tak aktywnie w projekcie jak kiedyś.

Zanim przystąpimy do implementacji gorąco zachęcam do zapoznania się z poprzednim artykułem poświęconym log4net, a także wstępniakiem do całej serii Wystarczy, że jako czytelnik poznasz zasadę rejestracji zdarzeń w log4net, gdyż w NLog jest ona analogiczna.

Zaczynamy przygodę z NLog

Pierwsze co musimy zrobić, to ściągnąć binarki z oficjalnej strony projektu. Ja do celów tego artykułu wykorzystam wersję nlog-1.0-setup.exe. Dzięki tej paczce oprócz samych plików dll otrzymamy także dokumentację i zbiór przykładów. Po instalacji dodajemy referencję do NLog.dll znajdującym się w folderze net-2.0. Następnie do projektu dodajemy plik konfiguracyjny NLog.config - plik ten zostanie automatycznie wczytany i NLog z niego pobierze sobie konfigurację. Ustawmy mu właściwość "Copy to Output Directory" na: "Copy always". Wyjście naszych logów - o priorytetach: Debug wzwyż - będziemy kierować na konsolę, dlatego do pliku konfiguracyjnego powinniśmy dodać wpis: "targets".

<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="console" xsi:type="Console"
            layout="${longdate}|${level}|${message}"/>
  </targets>
</nlog>

Cel mamy zdefiniowany, teraz pora na definicję zasad: tak jak ustaliliśmy wcześniej interesuje nas jedynie logowanie zdarzeń o priorytecie Debug i wyższych. Dodajmy więc definicję rules poniżej definicji targets:


<rules>
    <logger name="*" minlevel="Debug" writeTo="console" />
</rules>

Sama zasada wstawiania zdarzeń do logów jest praktycznie identyczna jak w log4net. Pierwsze co musimy zrobić to otrzymać instancję klasy Logger. Robimy to wywołując statyczną metodę klasy LoggerManager:


using System;
using NLog;
namespace NLogSample
{
    class Program
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();
        static void Main(string[] args)
        {
            logger.Debug("Nasz pierwszy komunikat NLog!");
        }
    }
}

Po testowym uruchomieniu efekt powinien być podobny do poniższego:


nlog1


Ok, ale logowanie na konsolę to na pewno nie jest to, co docelowo chcielibyśmy osiągnąć. Spróbujmy zatem tym razem logować zdarzenia do pliku tekstowego: chyba jednej z czytelniejszej formy logowania zdarzeń (choć problem z filtrowaniem ich to inna sprawa). Aby nie niszczyć pracy jaką włożyliśmy w poprzedni przykład :-) nasza aplikacja do pliku tekstowego będzie logowała zdarzenia o priorytetach Error i wyższych, reszta niech idzie na konsolę, tak jak było to dotychczas. Dodajmy więc nową regułę do pliku konfiguracyjnego NLog.config:


<logger name="*" minlevel="Error" writeTo="file" />

Czas na dodanie wpisu konfiguracyjnego samego celu:


<target name="file" xsi:type="File"
            layout="${longdate} ${logger} ${message}"
            fileName="${basedir}/logfile.txt"
            keepFileOpen="false"
            encoding="iso-8859-2" />

Myślę, że poszczególne atrybuty są na tyle czytelne, że nie trzeba ich szerzej opisywać, ciekawskich odsyłam do dokumentacji :-) Po modyfikacjach plik NLog.config powinien wyglądać następująco:


<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="console" xsi:type="Console"
            layout="${longdate}|${level}|${message}"/>
    <target name="file" xsi:type="File"
            layout="${longdate} ${logger} ${message}"
            fileName="${basedir}/logfile.txt"
            keepFileOpen="false"
            encoding="iso-8859-2" />
  </targets>
  <rules>
        <logger name="*" minlevel="Debug" writeTo="console" />
        <logger name="*" minlevel="Error" writeTo="file" />
  </rules>
</nlog>

Czas na odrobinę kodu, przypominam dodajemy logowanie zdarzeń typu Error do pliku tekstowego:


using System;
using NLog;
namespace NLogSample
{
    class Program
    {
        private static Logger logger = LogManager.GetCurrentClassLogger();
        static void Main(string[] args)
        {
            logger.Debug("Nasz pierwszy komunikat NLog!");
            int a = 1;
            int b = 0;
            try
            {
                int c = a / b;
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
        }
    }
}

Wystarczy nam teraz uruchomić aplikację i przekonać się, że w folderze ze skompilowanym programem został utworzony plik logu, w którym będą lądowały wyjątki przechwycone w blokach try-catch.
Oczywiście to dopiero ułamek potęgi biblioteki NLog. Oprócz jej niewątpliwej szybkości (sprawdzonej w kilku benchmarkach), należy odnotować mnogość celów dla zdarzeń, czyli:

• Class Description
• ASPNetTraceTarget 
• ChainsawTarget 
• ConsoleTarget 
• DatabaseParameterInfo
• DatabaseParameterInfoCollection
• DatabaseTarget
• DebuggerTarget
• DebugTarget
• FileTarget
• FormControlTarget 
• MailTarget
• MemoryTarget
• MessageBoxTarget
• MethodCallParameter
• MethodCallParameterCollection
• MethodCallTarget
• NetworkTarget
• NLogViewerTarget 
• NullTarget 
• RichTextBoxTarget
• TraceTarget 
• WebServiceTarget

Jako zadanie domowe mogę zachęcić Was do zalogowania zdarzeń do kilku innych wyjść.