sobota, 6 lipca 2013

Log4net, czyli logowanie błędów w .NET

W pracy programisty bardzo ważne jest logowanie błędów. Gorsze od nie logowania błędów jest tylko błędne logowanie błędów (np. poprzez napisanie własnego logera, co niestety miałem już okazję widzieć w praktyce). Aby poprawnie logować błędy, najlepiej użyć jakiegoś gotowego rozwiązania.

Dla aplikacji typu '.net' np. asp.net (ale z wyłączeniem aplikacji typu sharepoint) jednym z gotowych, darmowych rozwiązań jest biblioteka log4net. Biblioteka dostępna jest pod licencją apache 2.0 (link do wikipedii).

Początkowo myślałem, aby się rozpisywać, jak skonfigurować oraz obsługiwać tą bibliotekę, ale myślę, że inni zrobili to znacznie lepiej, więc odsyłam do linków:
Łukasz Gąsior - > log4net-logujemy-zdarzenia-w-aplikacji/
Codeproject.com - log4net-Tutorial
Log4net - manual introduction

Przykładowa konfiguracja:
- web.config
    <configSections>
        <sectionGroup name="applicationSettings" type="System.Configuration.
ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
            <section name="test.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        </sectionGroup>
      <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,Log4net"/>
    </configSections>
  <log4net>
    <root>
      <level value="DEBUG"/>
      <appender-ref ref="LogFileAppender"/>
    </root>
    <appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
        <param name="File" value="C:\dev\test\test\Logs\test_log.log"/>
        <lockingModel type="log4net.Appender.FileAppender+MinimalLock"/>
        <datePattern value="dd.MM.yyyy" />
        <staticLogFileName value="true" />
        <appendToFile value="true" />
        <rollingStyle value="Date" />
        <maxSizeRollBackups value="10" />
        <maximumFileSize value="5MB" />
        <layout type="log4net.Layout.PatternLayout">
          <param name="ConversionPattern" value="%date [%thread] %-5level %type.%method - %message%newline"/>
        </layout>
    </appender>
  </log4net>

-global.asax:
        protected void Application_Start(object sender, EventArgs e)
        {
            log4net.Config.
XmlConfigurator.Configure();
        }

In application:
protected static readonly ILog log = LogManager.GetLogger(System.
Reflection.MethodBase.GetCurrentMethod().DeclaringType);

use:
log.Info("foo bar");

piątek, 5 lipca 2013

T-SQL select po kilku ostatnich znakach

Często zdarza nam się konieczność pisania zapytania typu 'select' po ciągach znaków, typu varchar. Czasami potrzebujemy wyszukiwać lub wyświetlać wyniki tylko po części wyrazu. Wtedy najczęściej wystarczy funkcja SUBSTRING. A co, jeśli potrzebujemy wyszukać część wyrazu po kilku ost. znakach (np. dane, które posiadamy są różnej długości*)?? Wtedy z pomocą przychodzi nam funkcja RIGHT

SELECT RIGHT(column, 3)


* - przykład 'życiowy'. Dane, które przychodzą z jednego, z zewnętrznych syst. informatycznych, z którym się integrujemy czasami przychodzą w formacie '0000xxx' (np. 0000123), a innym razem jako 'xxx' (np. '123').

DevExpress AspxGridView filtrowanie w zakresie dat/liczb od-do

O ile standardowy devexpress aspxgridview nie posiada domyślnie wbudowanego filtru wyboru daty w zakresie od-do (standardowo można wybrać datę z kalendarzyka w 'popupie', lub z góry zdefiniowane wartości 'przedziału' jako 'drop down list') to od czego mamy support i genialne wręcz możliwości rozszerzania domyślnej funkcjonalności jakie oferują nam kontrolki devexpressa.

Zakres filtrów z datami 'od-do' został opisany w tym oto zgłoszeniu supportu, natomiast utworzenie odpowiedniego filtru dla wartości numerycznych jest bliźniaczo podobne poprzez utworzenie klasy
NumericSelector , która jest klasą bliźniaczą klasy DateSelector.

środa, 26 czerwca 2013

Usuwanie elementu kolekcji podczas iterowania po tej kolekcji.

Kolekcje dynamiczne w jakie wyposażone są języki c# oraz java to wielki krok na przód w porównaniu do standardowego języka c++. Oczywiście w c++ były tablice i wskaźniki, a rozszerzeniach języka c++ kolekcje, jednak operowanie na dynamicznych listach z punktu widzenia programisty jest dużo bardziej wygodne i bezpieczne na kolekcjach niż na tablicach (ehh, te wskaźniki). Główna zaleta kolekcji polega bowiem na tym, że dynamicznie zmieniają one swoją objętość podczas dodawania i usuwania elementów. Takie zachowanie ma mnóstwo plusów, ale ma też jeden minus, tj. jeżeli iterujemy pętlą po kolekcji generycznej w standardowy sposób (od elementu 0, do elementu n) to usuwając elementy z listy, dynamicznie zmniejszamy jej wielkość, a co za tym idzie pętla będzie próbowała się odwołać do większej ilości elementów niż jest w kolekcji, a to spowoduje wystąpienie wyjątku. Oczywiście jest na to prosty i wygodny sposób, tj. iterowanie po kolekcji 'od tyłu'. Rozwiązanie zaczerpnięte z forum stackoverflow.com

var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
    if (list[i] > 5)
     list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));

wtorek, 11 czerwca 2013

Odwołanie się do kontrolki DevExpress za pomocą javascript

Jednym z ważnych aspektów pisania efektywnego i przyjaznego dla użytkownika kodu aplikacji webowych, jest umiejętne wykorzystywanie języka javascript umieszczonego w przeglądarce. Aby efektywnie korzystać z tego języka, należy umieć odwoływać się do obiektów.
Standardowo, w języku javascript do obiektów dokumentu odwołujemy się poprzez metodę 'document.getElementById()':

<dx:ASPxButton ID="ASPxButton1" runat="server" AutoPostBack="False" Text="Get text">
</dx:ASPxButton>

<script type="text/javascript" >
     var editorClientId = "<%=ASPxButton1.ClientID%>";
     var editor = document.getElementById(editorClientId);
     //Do something
</script>


Niestety, ale taka, standardowa dla języka javascript opcja, w przypadku kontrolek DevExpressa nie zadziała. W przypadku kontrolek DevExpressa, aby odwołać się do naszych kontrolek w języku javascript mamy dwie możliwości:

a) nadać kontrolce sztywne 'client id', tak jak zostało to opisane w tej odpowiedzi supportu.. Niestety takie rozwiązanie ogranicza nas do jednej instancji tej kontrolki na stronie:

<dx:ASPxPopupControl ID="ASPxPopupControl1" runat="server" ClientInstanceName="popupControl" ></dx:ASPxPopupControl>

 <script type="text/javascript" >
  popupControl.Show();
 </script>

b) wykorzystać metodę 'ASPxClientControl.GetControlCollection().GetByName()', która jest DevExpressowym odpowiednikiem 'document.getElementById()'. Sposobów jak to zrobić jest kilka. Jeden z nich umieszczony został w dokumentacji. Inny przykład:

        <dx:ASPxGridView ID="grid" runat="server" CssClass="gridRelatedDocs" AutoGenerateColumns="False" Width="100%"
        GridLines="None" style="padding-left: 0px;padding-right: 0px;">
            <Border BorderStyle="None" BorderWidth="0px" />
            <SettingsBehavior AllowDragDrop="False" />
            <Settings ShowFilterRow="True" />
            <SettingsPager >
                <Summary Visible="False" />
            </SettingsPager>
        </dx:ASPxGridView>

<script language="javascript" type="text/javascript">
    function DoSomething() {

        var grid2 = $('.gridRelatedDocs');
        if (grid2 != null && grid2[0] != null) {
            var grid = ASPxClientControl.GetControlCollection().GetByName(grid2[0].id);
            //grid.DoSomething
        }
    }
 </script>

Generalnie sposób nr. 2 jest bardziej przyjazny i uniwersalny. Wprawdzie najpierw musimy ustalić id elementu w hierarchii struktury drzewa DOM, ale posiadając już standardowy, 'javascriptowe' id obiektu możemy się nim posługiwać w standardowy sposób. Wykorzystanie rozwiązania z 'ASPxClientControl.GetControlCollection().GetByName'  pozwala na umieszczenie wielu kontrolek tego samego typu na jednej stronie asp.net.

poniedziałek, 10 czerwca 2013

Wstep do kontrolek DevExpress

Jak zapewne wielu programistów wie, jedną z najgorszych rzeczy, jakie można robić będąc programistą, to wymyślanie koła od nowa. Aby tego nie robić, powstały frameworki (np. .NET Framework), wzorce projektowe, rozszerzalne biblioteki (np. jQuery, pdf-libraries) i wiele, wiele innych. Część udostępnianych na darmowych licencjach (np. Licencja X11 (MIT)), a część na licencjach komercyjnych.
Takim przykładem komercyjnego oprogramowania, a dokładniej kontrolek wykorzystywanych w środowisku '.NET' są kontrolki firmy  DevExpress. Kontrolki, które nie są tanie (link do cennika) i kupowane są 'per developer'. Tak, moi mili. Te ceny, które są tam umieszczone dotyczą ceny, za możliwość wykorzystywania oprogramowania przez pojedyńczego programistę i kształtują się od $900 za najmniejszy pakiet (np. dla programisty asp.net) do pakietu full ($2199 per programista).

Co za tą cenę dostajemy?
Hmmm, chyba najlepsze kontrolki programistyczne, jakie można dostać w .net ;)
Programując z ich wykorzystaniem programista naprawdę zyskuję sporą przewagę nad rozwiązaniami darmowymi, a co za tym idzie programowanie idzie szybciej, sprawniej, jest ładniejsze i zawiera mniej błędów. Przede wszystkim uzyskujemy kod wykorzystywany i sprawdzony przez miliony ludzi. Firma devExpress wygrywała ze swoimi kontrolkami wiele międzynarodowych konkursów, przez co jej popularność rosła, a wraz z nią ilość ludzi którzy bezpośrednio (developerzy) oraz pośrednio (użytkownicy ich programów) z nich korzystali na co dzień. Jedną z największych zalet wynikających z tych kontrolek jest właśnie to, że jak coś się miało popsuć, lub 'nie wyjść' to bardzo prawdopodobne, że wcześniej popsuło się komuś innemu i ekipa z devxpressa już ten problem rozwiązała, lub właśnie nad nim pracuje ;)
Oczywiście, nie ma róży bez kolców, ale o tym nieco później.

Najpierw jednak przyjrzyjmy się tym kontrolkom nieco bliżej. Jak przykład użyję kontrolek asp.net, jako, że są to kontrolki webowe i istnieje całkiem niezłe 'on-line' demo. Jedną z najlepszych, a zarazem najczęściej używanych jest DevExpressowy odpowiednik AspxGridView.
Zalecam zapoznanie się z demem tego grida, ponieważ posiada naprawdę potężne możliwości (np. utworzenie rozwiązania, wyświetlającego 300.000 rekordów w kilka min. z rewalacyjną, jak na taką ilość danych szybkością wyświetlania, sortowania, filtrowania itp.).

Do tego dochodzą wszelakie możliwości kontrolek DevExpressa, czyli multum opcji i pełna konfigurowalność (a w pakiecie ultimate również kody źródłowe kontrolek). Po tym, jak programista zobaczy, ile jest opcji konfiguracyjnych dla danej kontrolki by deafult (a drugie tyle w tutorialach i Q&A na forum wsparcia) to później zwykłe .net-owe kontrolki wyglądają mega blado.

Tak jak już zostało wspomniane, aspxGridView nie jest jedyną kontrolką, jaka isntieje w pakiecie. Generalnie zasada jest taka, że każda kontrolka wystepująca w standardowym GUI .NET Framework ma tutaj swoje devExpressowego odpowiednika. Do tego dochodzą jeszcze inne, mniej lub bardziej przydatne kontrolki standardowo nie występujące we frameworku.

Ale nie ma róży bez kolców. Oto kilka mniej przyjemnych aspektów, które należy wziąć pod uwagę w momencie, gdy nastąpi już pierwszy 'efekt wow'.
Więc po kolei:
- cena, która jest dosyć spora, bo liczona per programista
-  problemy z instalacją w środowisku sharepoint - zapewne będzie to temat jednego z przyszłych wpisów. Generalnie udało nam się to zwalczyć własnymi siłami dla pojedyńczego serwera, za pomocą ręcznego instalowania paczek '.wsp' oraz ręcznych wpisów do web.config (automaty dostarczane przez producenta nie zadziałały, a wsparcie techniczne nie było nam w stanie pomóc), aczkolwiek syt. 'farmy serwerów', w której mamy dostęp do pliku web.config tylko jednego serwera nadal jest dla nas problematyczna.
- na słabszych sprzętowo maszynach,  obciążenie procesora/pamięci ram powodowało randomowe błędy krytyczne visual studio powodujące jego zamknięcie w trybie awaryjnym, w momencie włączania debuggera. O dziwo, problem ten występował tylko i wyłącznie dla aplikacji typu sharepoint.
- takie sobie wsparcie techniczne, które stara się pomóc, jednak z własnego doświadczenia wiem, że iż mimo, że jest całkiem miłe, to działa średnio sprawnie.


Generalnie temat warty rozważenia, aczkolwiek w przypadku firm typowo sharepointowych mocno wątpliwy, z uwagi na dodatkowe, mało znane producentowi problemy związane z developowaniem tych kontrolek w środowisku sharepoint.

niedziela, 9 czerwca 2013

Kilka wersji biblioteki jQuery na tej samej stronie

jQuery jest bardzo fajną i przydatną biblioteką javascriptową. Standardowo posiada jednak pewną wadę. W momencie, gdy kilka komponentów umieszczonych na stronie próbuje wczytać swoje biblioteki jQuery, wyrzuca dziwne błędy (jQuery przestaje działać częściowo lub w całości). Jest to związane z faktem, że system nie wie, do której konkretnej biblioteki ma się odwołać poprzez znacznik '$'. Jak uniknąć błędów, związanych z faktem, że na stronie może być umieszczony jeden lub kilka niezależnych komponentów, a każdy z nich niezależnie wymaga do działania biblioteki jQuery opisałem w jednym z poprzednich wpisów na blogu.

Życie jednak pokazuje, że czasami jesteśmy zmuszeni do wykorzystania na jednej stronie asp.net kilku bibliotek jQuery w różnej wersji biblioteki. Np. do 95% syt. chcemy wykorzystywać bibliotekę w wersji "stabilnej', natomiast do 5% syt. chcemy wykorzystać najnowszą funkcję biblioteki dostępnej jedynie w niestabilnej wersji biblioteki. Na szczęście biblioteka jQuery pozwala na zastosowanie takiego rozwiązania.

<script src="/_layouts/scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="/_layouts/scripts/jquery-ui-1.8.24.custom.min.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
var j182 = $.noConflict(true);$(document).ready(function(){                     
                        j182("#featured").tabs().tabs("rotate", 5000, true);
                        });//]]>
</script>


dodatkowo, po stronie kodu c# wpisujemy:

            if (!cs.IsClientScriptBlockRegistered("j182"))
                cs.RegisterClientScriptBlock(this.GetType(), "j182", @"var j182 = $.noConflict(true);", true);


W tym przypadku, mamy wczytane 2 biblioteki jQuery. Do pierwszej, w wersji 1.8.2 odwołujemy się normalnie, tj. poprzez znacznik '$', natomiast do drugiej, w wersji 1.8.24 poprzez znacznik przez nas zdefiniowany, tj. poprzez znacznik 'j182'.