C# 4.0 – parametr domyślny

W mojej pierwszej “zawodowej” pracy na stanowisku programisty miałem okazję programować w VB.NET. Wbrew wielu opiniom uważam, że to bardzo przyjazny język i programuje się w nim bardzo fajnie.

Po przesiadce na C#, poza koniecznością wstawiania średnika na końcu każdej linii, zaskoczył mnie brak możliwości zdefiniowania parametru domyślnego w metodzie. Trochę to zajęło, ale i C# w końcu “dorobił” się tej funkcjonalności. Parametry domyślne w C# zostały wprowadzone w wersji C# 4.0, czyli w .NET 4.0. czytaj dalej

log4net – logujemy zdarzenia w aplikacji

Dzisiaj chciałbym poruszyć ważny element tworzenia aplikacji – logowanie zdarzeń. Odpowiednio przygotowane logi są często jedynym sposobem na zdiagnozowanie problemu w aplikacji, dlatego warto o tym pamiętać i z logowania korzystać.

Logowanie można przeprowadzić na wiele sposobów – ja chciałbym opisać przykład oparty na darmowej bibliotece log4net.

Temat ten podzieliłem na trzy części:

  • dzisiaj pokażę jak korzystać z log4net
  • w następnym poście pokażę, jak czytać/analizować logi
  • na koniec opiszę podstawową konfigurację log4net

To zaczynamy:
bibliotekę pobieramy ze strony: http://logging.apache.org/log4net/download.html. Z pobranego archiwum wypakowujemy plik: log4net.dll (incubating-log4net-1.2.10.ziplog4net-1.2.10binnet2.0releaselog4net.dll) i wgrywamy go np. do katalogu “lib“. Następnie dodajemy referencję do tego pliku.

log4net1

W swoich aplikacjach korzystam z takiej klasy:

[sourcecode language=”csharp”]
public class LogHelper
{
static LogHelper()
{
var confFile = ConfigurationSettings.AppSettings.Get("log4net.config");
var fi = new FileInfo(confFile);
XmlConfigurator.Configure(fi);
}

public static ILog GetLog()
{
return LogManager.GetLogger("WebAppLog");
}
}
[/sourcecode]

Jak widać w pliku Web.config podajemy ścieżkę do pliku konfiguracyjnego, czyli:

[sourcecode language=”xml”]
<appSettings>
<add key="log4net.config" value="conflog4net.config"/>
</appSettings>
[/sourcecode]

Brakuje jeszcze zawartości pliku log4net.config:

[sourcecode language=”xml”]
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender,log4net">
<file value="logstest_log.log" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
<param name="StaticLogFileName" value="true"/>
<appendToFile value="true" />
<param name="RollingStyle" value="Date"/>
<param name="DatePattern" value="yyyy-MM-dd"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %type.%method – %message%newline"/>
</layout>
</appender>

<logger name="WebAppLog">
<level value="ALL" />
<appender-ref ref="RollingLogFileAppender" />
</logger>
</log4net>
[/sourcecode]

Podana konfiguracja zapisuje logi do pliku (może to być również baza danych, e-mail, konsola lub inne źródło) – file określa, do jakiego pliku będą zapisywane logi, a layout określa format zapisu logów.

Samo logowanie jest operacją niezwykle prostą:

[sourcecode language=”csharp”]
LogHelper.GetLog().Info("My sample comments");
[/sourcecode]

lub

[sourcecode language=”csharp”]
catch (Exception ex)
{
LogHelper.GetLog().Error("Error occurred!", ex);
}
[/sourcecode]

log4net dostarcza kilka poziomów logowania:

  • Debug
  • Info
  • Warn
  • Error
  • Fatal

Nazwy poziomów logowania są bardzo czytelne i nie wymagają większego opisu.

Powyższy kod w logu zapisać może coś takiego:

[sourcecode language=”text”]
2009-12-07 22:22:33,202 [8] INFO  LogForNetWebSample._Default.Page_Load – My sample comments
2009-12-07 22:22:33,292 [8] ERROR LogForNetWebSample._Default.Page_Load – Error occurred!
System.DivideByZeroException: Attempted to divide by zero.
at LogForNetWebSample._Default.Page_Load(Object sender, EventArgs e) in Default.aspx.cs:line 14
[/sourcecode]

Jak widać log zawiera wiele cennych dla nas informacji – wiemy, kiedy i co się zdarzyło oraz w jakiej metodzie. Wiemy również, co działo się w aplikacji zanim wystąpił wyjątek.

Osobiście jestem zwolennikiem logowania jak największej ilości zdarzeń w naszej aplikacji – użytkownik wchodzi na stronę, klika button A, pobrano dane użytkownika, itp – jako poziom Debug. Przy przenoszeniu aplikacji na serwer produkcyjny możemy ograniczyć poziom logowania i logować jedynie logi z poziomu Error, Fatal czy Warn – bez zmiany kodu aplikacji!
log4net jest biblioteką bardzo elastyczną i posiada wiele parametrów konfiguracyjnych.

Oczywiście podczas logowania trzeba uważać, żeby nie zalogować danych poufnych – np. haseł.

Dzisiaj to tyle – zachęcam do zabawy z log4net i czytaniem logów – tylko uwaga – TO UZALEŻNIA!! :)

Quick Tip: 05. waliduj dane w formacie w jakim je wyświetlasz

Często dane, które posiadamy musimy odpowiednio sformatować przed ich wyświetleniem.
Jeżeli takie dane musimy zwalidować, to warto zadbać, aby walidowane dane były  w takim samym formacie jak je wyświetlamy.

Prosty przykład:

Powiedzmy, że mamy metodę pobierającą kwotę faktury:

[sourcecode language=”csharp”]

var invoiceBalance = GetInvoiceBalance();

[/sourcecode]

Kwotę tą otrzymujemy z dokładnością do 4 miejsc po przecinku.
Jednak przez wyświetleniem formatujemy ją:

[sourcecode language=”csharp”]

litInvoiceBalance.Text = invoiceBalance.ToString("C");

[/sourcecode]

Co w wyświetli nam np. 100,00 zł.
Jak widać nasza zmienna wyświetlana jest z dokładnością do 2 miejsc po przecinku.

Dodatkowo załóżmy, że jeżeli pobrana kwota jest większa od 0, umożliwimy użytkownikowi zaznaczenie RadioButton’a, czyli:

[sourcecode language=”csharp”]

if (invoiceBalance > 0)
{
rbMakePayment.Enabled = true;
}

[/sourcecode]

Niby wszystko ok – aplikacja działa. Jeśli kwota jest większa od 0 możemy zaznaczyć RadioButton’a, a jeśli nie to nie możemy.

Problem pojawi się w sytuacji, kiedy nasza procedura zwróci np. 0,0010.
Co wówczas zrobi nasz program? Wyświetli 0,00 zł, ale jednocześnie pozwoli zaznaczyć RadioButton’a :(
Dzieje się tak, ponieważ 0,0010 zaokrąglone do dwóch miejsc po przecinku da nam 0,00, ale podczas walidowania kwota jest większa od zera.

Tego typu błędy są czasami ciężkie do wykrycia – kompilator nic nie zgłosi, a i sam błąd występuje rzadko.

Rozwiązaniem w tym przypadku jest zaokrąglenie naszej kwoty przed wyświetleniem i zwalidowaniem, czyli:

[sourcecode language=”csharp” highlight=”3″]
var invoiceBalance = GetInvoiceBalance();

invoiceBalance = Math.Round(invoiceBalance, 2);

litInvoiceBalance.Text = invoiceBalance.ToString("C");

if (invoiceBalance > 0)
{
rbMakePayment.Enabled = true;
}

[/sourcecode]

Warto zwrócić uwagę na takie sytuacje.

Jak pobrać PublicKeyToken – GetAssemblyDetails

W jednym z projektów, nad którym ostatnio pracowałem, musiałem dodać referencje do pewnej biblioteki, czyli np. standardowe:

[sourcecode language=”xml”]
<add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
[/sourcecode]

Niby wszystko ok, ale to PublicKeyToken – trochę trzeba się naklikać, żeby tą wartość uzyskać.

Jako osoba ceniąca “proste” życie napisałem program, który robi to za mnie – GetAssemblyDetails :)

GetAssemblyDetails jest standardową aplikacją konsolową, którą dodatkowo można wywołać z menu kontekstowego plików .dll oraz .exe

Jak tego programu używać:

GetAssemblyDetails -f “ścieżka do assembly” – pobiera dane assembly
np. GetAssemblyDetails -f c:Program FilesMicrosoft ASP.NETASP.NET MVC 1.0AssembliesSystem.Web.Mvc.dll

GetAssemblyDetails -r – dodaje program do menu kontekstowego

GetAssemblyDetails -u – usuwa program z menu kontekstowego

Wystarczy skopiować tekst wygenerowany przez program i voila :)

POBIERZ  GetAssemblyDetails.exe

I jeszcze parę screenów:

assembly1

assembly2

Quick Tip: 04. przeszukuj kolekcje z where zamiast foreach

LINQ udostępnia metodę where, która umożliwia przeszukiwanie kolekcji tak jak foreach.

Przykładowo, zamiast:

[sourcecode language=”csharp”]
var polishCustomers = new List<Customer>();

foreach (var customer in customers)
{
if (customer.Country == "Poland")
polishCustomers.Add(customer);
}
[/sourcecode]

możemy użyć

[sourcecode language=”csharp”]
var polishCustomers = customers.Where(x => x.Country == "Poland");
[/sourcecode]

czyli krótko, zwięźle i na temat :)

Oczywiście wcześniej musimy dodać using System.Linq;

C# Interview Questions

Do tej pory głównie tworzyłem aplikacje ASP.NET w VB.NET. Tak się jednak narobiło, że w życiu mi się trochę pozmieniało i muszę nadrobić zaległości w C#. Więcej szczegółów podam wkrótce. Teraz chciałbym przedstawić Wam ciekawą listę pytań dotyczących C#. Aktualnie lista zawiera 427 pytania ale ciągle się powiększa. Jest to takie forum, gdzie każdy może pytanie zadać i każdy może udzielić odpowiedzi.
Moim zdaniem świetny materiał na odświeżenie oraz sprawdzenie swojej wiedzy.

Lista dostępna pod adresem:
http://www.geekinterview.com/Interview-Questions/Microsoft/C-Sharp

Warto dodać, że strona zawiera wiele podobnych list dotyczących np. ADO.NET 2.0, ASP.NET czy baz danych. Pełna lista dostępna jest pod adresem: http://www.geekinterview.com/Interview-Questions

Jeśli znacie podobne strony podajcie je w komentarzach.