piątek, 5 października 2012

Biblioteka Vici CoolStorage dla .NET

Dzisiaj postanowiłam bliżej przedstawić bibliotekę ułatwiającą korzystanie z bazy danych, którą wykorzystuję od początku mojej pracy w .NET.
Vici CoolStorage jest biblioteką dla .NET pozwalającą mapować obiekty relacyjnej bazy danych. Biblioteka ta jest bardzo łatwa w użyciu. Wspiera takie bazy danych jak: SQL ServerMySQLSQLiteMS Access i VistaDB.

Bibliotekę Vici CoolStorage można pobrać z tej strony: http://viciproject.com/wiki/Projects/CoolStorage/Download
Na tej stronie również znajdziemy dokumentację z opisem, jak skonfigurować połączenie z bazą danych oraz jak korzystać z samej biblioteki: http://viciproject.com/wiki/Projects/CoolStorage/Doc/UserGuide

Po pobraniu biblioteki w zależności czy jest to kod źródłowy czy skompilowana biblioteką, dołączamy ją odpowiednio do naszego projektu w Visual Studio (albo przez dodanie do solucji projektu biblioteki, albo poprzez dołączenie referencji do pliku .dll).

Następnym krokiem jest dodanie kilku linijek w pliku web.config :
1. W configuration >> configSections dodajemy definicję nowej sekcji:
<section name="CoolStorage" type="System.Configuration.NameValueSectionHandler"/>
2. Potem w configuration dodajemy sekcję CoolStorage, w której umieszamy connection string do naszej bazy danych, w moim przypadku wygląda to tak:
<CoolStorage>
    <add key="Connection.zawodycon" value="CSDataProviderMySql, Vici.CoolStorage / Server=127.0.0.1;Port=3306;Database=zawody;UID=root;PWD=mojehaslo;Allow Zero DateTime=true;default command timeout=500;Connection Timeout=500;"/>
  </CoolStorage>
Po skonfigurowaniu połączenia można przejść do korzystania z biblioteki.
Do klasy w naszym modelu danych trzeba dołączyć dwie biblioteki:
using Vici.CoolStorage;
using System.ComponentModel;
Każda tabela w bazie danych może być zmapowana na dokładnie jedną klasę. Do klasy należy dołączyć atrybut MapTo, w moim przypadku wygląda on tak:
[MapTo("zawody", "zawodycon")]
, gdzie "zawody" to nazwa mojej tabeli, na którą mapowana będzie klasa, natomiast "zawodycon" to nazwa połączenie z bazą danych, które wcześniej ustawiłam w web.configu (<add key="Connection.zawodycon" ... ).

Cała moja klasa wygląda tak:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Vici.CoolStorage;
using System.ComponentModel;

namespace Dane

{
    [DataObject]
    [MapTo("zawody", "zawodycon")]
    public abstract partial class Zawody : CSObject<Zawody, int>
    {
        public abstract int id { get; }
        public abstract string nazwa { get; set; }
        public abstract string opis { get; set; }
        public abstract DateTime data { get; set; }

/* Określenie relacji tabeli zawodów z tabelą zawodników

  Pozwoli to na odwoływanie się poprzez obiekt klasy Zawody,
  do listy zawodników przypisanych do tych zawodów */
        [OneToMany(LocalKey = "id", ForeignKey = "id_zawody")]
        public abstract CSList<Zawodnicy> Zawodnicy { get; }

/* Metoda pobierająca zawody o podanym ID */

        public static Zawody PobierzZawody(int id)
        {
            return Zawody.ReadSafe(id);
        }

/* Metoda pobierająca listę wszystkich zawodów */

        public static List<Data.Zawody> PobierzWszystkieZawody()
        {
            return Zawody.List().ToList();
        }

/* Metoda sprawdzająca czy takie same zawody nie zostały już przypadkiem dodane */

        public static bool CzyJuzDodano(string nazwa, DateTime data)
        {
            return Zawody.ReadFirst("nazwa = @nazwa AND data = @data", "@nazwa", nazwa, "@data", data) != null;
        }

/* Metoda dodająca nowe zawody */

        public static bool DodajZawody(string nazwa, string opis, DateTime data)
        {
            Zawody z = Zawody.New();
            z.nazwa = nazwa;
            z.opis = opis;
            z.data = data;
            return z.Save();
        }

            /* ciąg dalszy klasy ...*/


    }

}

Istnieje również możliwość pobrania danych z bazy bezpośrednio poprzez zapytanie sql. Jednak nie można rzutować wyniku zwróconego przez zapytanie na klasę abstrakcyjną, tak więc nasza klasa powinna wyglądać tak:
public class Zawody
{
        public int ID { get; set; }
        public string Nazwa { get; set; }
        public string Opis { get; set; }
        public DateTime Data { get; set; }
}
i wtedy możemy już wykonać zapytanie np. poprzez użycie metody RunQuery, która zwróci nam listę wyników. Parametr wstawiamy w zapytaniu jako nazwę z "@", i potem podmieniamy w metodzie wstawiając po przecinku nazwę paramteru i wartość.
var sql = "select id as ID, nazwa as Nazwa, data as Data from zawody z where z.data > @data";
var zawody = CSDatabase.Context["zawody"].RunQuery<Zawody>(sql, "@data", DateTime.Now.AddDays(-7)).ToList();
Dodatkowo zamiast RunQuery mamy do wyboru użycie metod RunSingleQuery (zwraca pojedynczy wynik), GetScalar (zwróci nam wybraną wartość) itd.
Jako przykład użycia GetScalar można podać zwrócenie ilości wyników
string sql = "select count(id) from zawody z where z.data > @data";
int ilosc = CSDatabase.Context["zawody"].GetScalar<int>(sql, "@data", DateTime.Now.AddDays(-7));
Szczegóły odnośnie użycia tych metod jak i wykorzystania metod odczytu i zapisu można znaleźć w dokumentacji :)

środa, 3 października 2012

Testujemy nasz serwis w wersji mobilnej

Z uwagi na to, że ostatnio pisaliśmy i wdrażaliśmy wersję mobilną naszego serwisu, potrzebne były narzędzie do testowania jak się sprawdza on na wersjach mobilnych. Chciałam wymienić w związku z tym kilka fajnych emulatorów do testowania:

wtorek, 25 września 2012

Usuwanie "brzydkich" znaczków z tabeli i duplikatów


W tym poście chciałam opisać coź z czym ostatnio miałam do czynienia w pracy, mianowicie usuwanie "brzydkich" znaków ze słów w tabeli, które kiedyś "wkradły się" do niej poprzez złe kodowanie w aplikacji.
Na wszelki wypadek zrobiłam kopie tej tabeli, a następnie mając listę znaków do zamiany, wykonałam następujące polecenia:
UPDATE slowa_clean SET slowo = REPLACE(slowo,'?','ż');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'e','ę');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'±','ą');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'3','ł');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'n','ń');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'¶','ś');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'a','ć');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'1','ź');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'—','Ż');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'E','Ę');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'!','Ą');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'L','Ł');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'N','Ń');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'¦','Ś');
UPDATE slowa_clean SET slowo = REPLACE(slowo,'A','Ć');

Z uwagi na to, że w mojej tabelce pojawiło się kilka zdublowanych słów (niektóre dobre dodały się już w obecnym dobrym kodowaniu), należało pozbyć się zduplikowanych wierszy, aby to zrobić stworzyłam nową tabelę i wykonałam następujące polecenie:
INSERT INTO slowa_clean2 SELECT * FROM slowa_clean GROUP BY slowo;
Na końcu podmieniłam nową tabelkę ze zmianami, a starą zachowałam pod inną nazwą (na wszelki wypadek ;) ). Natomiast tabelkę roboczą slowa_clean usunęłam.

RENAME TABLE slowa TO slowa_old;
RENAME TABLE slowa_clean2 TO slowa;

Oczywiście najlepiej pilnować, aby w ogóle nie musieć tego robić, czyli dbać o prawidłowe wprowadzanie danych do bazy :P

piątek, 14 września 2012

Wyrażenia regularne i RegExr

W pracy bardzo często przydaje się znajomość wyrażeń regularnych. Do tworzenia i testowania wyrażeń regularnych przydaje się świetny programik o nazwie RegExr. Można z niego skorzystać tutaj: http://gskinner.com/RegExr/ lub pobrać wersję desktopową z tego adresu: http://gskinner.com/RegExr/desktop/

A teraz kilka wyrażeń regularnych z wykorzystaniem w konkretnych metodach w C# :)

Metoda wyszukująca linki i podmieniająca je na znaczniki html:

public static string FormatURL(string str)
        {
            string url = string.Empty;
            Regex reg = new Regex("([^=\"<'])(http(s)?://([\\w+?\\.\\w+])+([a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ0-9\\~\\!\\@\\#\\$\\%\\^\\&amp;\\*\\(\\)_\\-\\=\\+\\\\/\\?\\.\\:\\;\\'\\,]*)?)", RegexOptions.IgnoreCase);
            Match m = reg.Match(str);
            if (m.Groups[1].Value != "") url = m.Groups[2].Value;
            str = reg.Replace(str, "$1<a href=\"$2\" target=\"_blank\" rel=\"nofollow\">$2</a>");
            return str;
        }


Kolejny przykład to dwie funkcje, które umożliwiają formatowanie treści ze znacznikami bbcode na naszej stronie :)

Formatowanie znacznika bbcode dla cytatu:


public static string FormatCytatu(string str)
        {
            Regex reg = new Regex(@"(\[quote=([\w .-]*)\])", RegexOptions.IgnoreCase);
            str = reg.Replace(str, "<div class=\"quote_box\"><div style=\"margin: 5px;\"><b>$2 napisał(a):</b><br /><i>");
            str = str.Replace("[/quote]", "</i></div></div>");
            return str;
        }



Funkcja formatująca czcionkę:

public static string FormatCzcionki(string str)
        {
            Regex reg = new Regex(@"(\[color=([a-zA-Z]*)\])", RegexOptions.IgnoreCase);
            str = reg.Replace(str, "<font color=\"$2\">");
            str = str.Replace("[/color]", "</font>")
            return str;
        }



poniedziałek, 27 sierpnia 2012

Czas na HTML5! :)

Obecnie jestem na etapie czytania ciekawej książki Matthew MacDonalda pt. "HTML5 nieoficjalny podręcznik". Książka jak widać po samym tytule omawia najnowszy standard języka HTML, jest napisana w bardzo przystępny sposób, posiada wiele ciekawych przykładów i doskonale ukazuje możliwości HTML5.



HTML5 posiada wiele nowych możliwości, i składa się z ponad 100 elementów. Listę znaczników można zobaczyć pod adresem: http://dev.w3.org/html5/markup/ , natomiast specyfikację języka można przejrzeć tutaj: http://dev.w3.org/html5/spec/ . Dla wszystkich chcących zapoznać się z nowym standardem gorąco polecam zarówno książkę jak i przegląd dokumentacji :)

wtorek, 3 kwietnia 2012

Textarea - atrybut resize

Już od jakiegoś czasu przeglądarki mają domyślnie włączoną możliwość zmiany rozmiaru pola tekstowego (textarea). Umożliwia to dostosowanie szerokości i wysokości pola poprzez złapanie za dolny prawy róg pola i przeciągnięcie w celu uzyskania wybranego rozmiaru.
Może i czasem będzie to dla nas przydatne, jednak czasem potrafi to nieźle namieszać w wyglądzie witryny, jeśli użytkownik zbytnio rozciągnie takie pole.
Jeśli nie chcemy, żeby nasze pole tekstowe wyglądało w ten sposób i oferowało taką możliwość to CSS3 umożliwia nam ustawienie atrybutu resize. Żeby całkowicie wyłączyć możliwość zmiany rozmiaru pola, dodałam w stylach:
Atrybut ten możemy także ustawić na inną wartość, np.:
- tylko zmiana szerokości: resize: horizontal;
- tylko zmiana wysokości:  resize: vertical;
- zmiana szerokości i wysokości: resize: both;
- wartość atrybutu dziedziczona: resize: inherit;


środa, 21 marca 2012

Użytkownicy online

Jednym z ostatnich moich zadań, było przygotowanie statusów użytkowników, które będą określały czy dany użytkownik jest online, czy też nie.

Projekt, w którym to realizuje korzysta z cachowania przy pomocy Redis'a, o którym pisałam we wcześniejszym poście. Funkcje są funkcjami wcześniej omawianymi z klasy RedisCache.

Z uwagi na to, że sesja również przechowywana jest w Redisie, korzystam w moim projekcie .NET z własnego provider'a sesji. Na początku myślałam, że będę mogła dodawać identyfikatory użytkowników do listy w cache'u przy logowaniu lub w zdarzeniu Session_Start w Global.asax i usuwać przy wylogowaniu bądź przy wywołaniu zdarzenia Session_End. Niestety, przy korzystaniu z własnego provider'a sesji zdarzenie Session_End nie będzie nigdy wywoływane.
Tak więc zrobiłam to inaczej, każdy użytkownik będzie przechowywany w redisie jako osobny klucz z wartością "1" jeśli jest dostępny. Klucz ten będzie dodawany bądź aktualizowany przy logowaniu i w każdym kontrolerze widoków projektu. Natomiast czas wygaśnięcia klucza zostanie ustawiony na 10 minut.


public static void DodajUzytkownikaOnline(string id)
        {
                string klucz = String.Format("online-{0}", id);
                RedisCacheProvider.RedisCache.Set<string>(klucz, "1", DateTime.Now.AddMinutes(10));
        }

        public static void UsunUzytkownikaOnline(string id)
        {
                 string klucz = String.Format("online-{0}", id);
                 RedisCacheProvider.RedisCache.Remove(klucz);
        }



public static bool CzyOnline(string id)
        {
                string klucz = String.Format("online-{0}", id);
                string status = RedisCacheProvider.RedisCache.Get<string>(klucz);
                if (status == "1")
                    return true;
                else
                    return false;
        }