RSS
 

Dziękujemy…

31 maj

Projekt dobiegł końca, a właściwie to został zawieszony z przyczyn niezależnych od naszego zespołu. Przyniósł nam on jednak dużo pożytku. W szczególności przysłużył się do stworzenia dwóch bardzo dobrych prac inżynierskich i pojawienia się na rynku pracy czwórki nowych inżynierów…

Oprócz tego dzięki niemu bardzo dobrze poznaliśmy ASP.NET MVC oraz jak mniemam w pewnym stopniu rozpopularyzowaliśmy nieco BLToolkit, który jest naprawdę świetnym narzędziem…

Ten wpis jest więc pożegnaniem… Dziękujemy wszystkim czytelnikom za pozytywny feedback dotyczący bloga, za odwiedziny i komentarze!

Bloga nie mamy oczywiście zamiaru zamykać, być może projekt zostanie jeszcze reaktywowany, ale przede wszystkim mamy nadzieję, że ten niemały zbiór wpisów okaże się jeszcze komuś przydatny.

Co do samych prac dyplomowych które napisaliśmy, to myślę, że o ile uczelnia nie będzie rościć sobie prawa do pierwszeństwa publikacji, to będziemy je mogli tutaj upublicznić tuż po wakacjach.

Pozdrawiamy,
zespół B21

 
No Comments

Posted in Zespół

 

Wysyłanie formularzy z AJAX

22 sty

Niedawno w realizowanym po pracy projekcie przyszło mi zaimplementować funkcjonalność sklepowego koszyka który dostępny był by na każdej stronie tworzonego serwisu. Projekt w prawdzie nie jest związany bezpośrednio z B21, ale rozwiązanie wydaje się być na tyle ciekawe, że warto je tutaj opisać.

Cała trudność w tym, że jednym z wymagań była możliwość zmieniania liczby zamówionych towarów w dowolnym momencie, bez wpływu na aktualnie przeglądaną zawartość.Do tego problemu można podejść na różne sposoby, np. zapamiętywać aktualne parametry. Najprostszym i najbardziej intuicyjnym rozwiązaniem wydaje się być jednak wykonanie operacji bez przesyłania całej strony wykorzystując wywołanie AJAX.

Do tego celu przygotowujemy partial view z reprezentujący zawartość naszego koszyka zawierającą jednocześnie formularz do modyfikacji ilości zamówionych towarów.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Store.ProductOrderInfo>>" %>

<% Html.BeginForm("BasketContent", "Order", FormMethod.Post, new { id = "basketForm" }); %>

<% foreach (var p in Model) {%>

<div>
    <%= Html.Hidden("Index", p.Product.Id)%>
    <%= Html.Hidden("[" + p.Product.Id + "].Product.Id", p.Product.Id)%>
    <%= Html.TextBox("[" + p.Product.Id + "].Amount", p.Amount)%>
    <%= Html.Encode(p.Product.Name) %>
</div>

<%} %>

<% Html.EndForm(); %>

<div>
    <a href="#" id="updateBasket">Przelicz</a>
</div>

Widok ten wykorzystywany jest przez akcje kontrolera służące do wyświetlania i aktualizacji zawartości koszyka.

public ActionResult Basket()
{
    var model = new BasketViewModel
    {
        OrderedProducts = BasketManager.Products,
        TotalCost = BasketManager.TotalCost
    };

    return PartialView(model);
}

[HttpPost]
public ActionResult Basket(IEnumerable<ProductOrderInfo> products)
{
    if (products != null)
        BasketManager.Update(products);

    return BasketContent();
}

Obiekt wykorzystywany w kontrolerze, czyli ProductOrderInfo reprezentuje oczywiście parę produkt i zamówiona ilość znajdująca się w koszyku.

Problemem który pojawia się  w tym momencie jest określenie sposobu w jaki względnie łatwo można wysłać cały formularz korzystając z technologii AJAX. Ręczne tworzenie długiej listy parametrów nie jest najlepszym pomysłem, tym bardziej, że istnieją gotowe rozwiązania… Do tego celu możemy posłużyć się wbudowaną w jQuery metodą .serialize() lub jeszcze bardziej uprościć sobie życie i wykorzystać gotową bibliotekę jquery.form. Pozwala ona automatycznie wysyłać formularze przy pomocy technologii AJAX i co najważniejsze automatycznie updatować wskazany element zawartością odpowiedzi przychodzącej z serwera. Wystarczy odpowiednio ustawić parametr target podając w nim selektor wskazujący właściwego div’a.

<script type="text/javascript">
    $('#updateBasket').click(function() {
    $('#basketForm').ajaxSubmit({ target: '#basket-content' });
        return false;
    });
</script>

I to już wszystko. Formularz zostanie automatycznie wysłany poprzez AJAX. Rezultat tego wywołania zastąpi dotychczasową zawartość diva w którym renderujemy nasz widok z koszykiem (w tym przypadku ma id basket-content).

Rozwiązanie eleganckie, przejrzyste i co najważniejsze proste w implementacji.

 
2 Comments

Posted in MVC

 

Święta Święta

24 gru

Witajcie w ten radosny świąteczny czas :)

Jesteśmy niezmiernie szczęśliwi, że nasza akcja „Paczka dla domu dziecka” zakończyła się pozytywnym odzewem ze strony czytelników bloga, oraz samego domu dziecka. Całkiem niedawno dostaliśmy kartki świąteczne wykonane przez dzieciaki z obdarowanej przez nas placówki…

Kartka z domu dziecka w Orzeszu

Kartka z domu dziecka w Orzeszu

Korzystając z okazji, chcemy jeszcze raz złożyć serdeczne życzenia dzieciakom z Orzeskiego Domu Dziecka!

Nie mniej szczere życzenia składamy wszystkim czytelnikom naszego bloga, osobom wspierającym ten projekt oraz wszystkim znajomym. Oczywiście nie możemy zapomnieć o naszym Promotorze. Panie Michale – mamy nadzieję, że nadchodzące święta będą dla Pana czasem wyciszenia i spokoju.

Wesołych Świąt!!!

 
1 Comment

Posted in Zespół

 

Generyczny CRUD w BLToolkit

18 gru

Budując architekturę wielowarstwową, wyraźnie oddzielając logikę biznesową od warstwy prezentacji podstawowym problemem jest wielokrotne powtarzanie kodu związanego z  operacjami create, read, update i delete czyli dodawania, pobierania, aktualizacji i usuwania obiektów z bazy danych.

Najprostszym rozwiązaniem jest tutaj wykorzystanie typów generycznych i użycie najbardziej ogólnych metod jakie daje nam nasza biblioteka do obsługi bazy danych… Jak wykonać generyczny CRUD w Business Logic Toolkit? Pokażę, na przykładzie zaczerpniętym wprost z naszego projektu.

Podstawą jest silne typowanie obiektów które mogą być w naszej generycznej klasie przetwarzane. Do tego celu na każdy obiekt z bazy danych nakładamy pusty interfejs IDatabaseObject, który jednoznacznie określi nam możliwość jego użycia.

public interface IDatabaseObject { }

Teraz część najważniejsza, czyli stworzenie generycznego repozytorium zawierającego metody do zapisu, aktualizacji i usuwania obiektów oraz propercję typu IQueryable pozwalającą wyciągać informacje z bazy danych i wykonywać dowolne zapytania. Repozytorium będzie klasą generyczną pozwalającą wybrać obsługiwany typ obiektu.

public class Repository<TDatabaseObject>
    where TDatabaseObject : class, IDatabaseObject
{
    protected readonly DataManager _db = DataManager.GetInstance();

    virtual public IQueryable<TDatabaseObject> All
    {
        get { return _db.GetTable<TDatabaseObject>(); }
    }

    virtual public void Insert(TDatabaseObject entity)
    {
        _db.Insert(entity);
    }

    virtual public void Update(TDatabaseObject entity)
    {
        _db.Update(entity);
    }
}

Dodatkowo możemy jeszcze założyć, że pewna pula tabel w bazie danych rozróżniana będzie według przypisanego im identyfikatora. Takie obiekty nazywać będziemy encjami i oznaczać kolejnym interfejsem IEntity.

public interface IEntity:IDatabaseObject
{
    long Id { get; set; }
}

Jak widać IEntity to jednocześnie IDatabaseObject tylko uzupełniony właśnie o pole z identyfikatorem.

Dlaczego więc nie przypisać identyfikatora wszystkim obiektom w bazie? Tutaj łatwo się domyślić, że czasem przydatne nam będą specyficzne tabele służące np. jako łączniki w relacjach many-to-many. W takich tabelach kluczem głównym są identyfikatory obu połączonych rekordów, ale sam rekord z tabeli łączącej nie posiada swojego identyfikatora.

Ostatnim krokiem jest dodanie rozszerzonego repozytorium które doda nam bardzo przydatne metody służące do wyciągania i usuwania obiektów po identyfikatorze. Ważnym jest tutaj także nadpisanie metody insert w taki sposób, aby nowo zapisanemu obiektowi przyporządkowywała od razu jego Id.

public class EntityRepository<TEntity> : Repository<TEntity>
    where TEntity : class, IEntity
{
    override public void Insert(TEntity entity)
    {
        var id = _db.InsertWithIdentity(entity);
        entity.Id = Convert.ToInt64(id);
    }

    virtual public TEntity Get(long id)
    {
        var result = from e in All
                     where e.Id == id
                     select e;

        return result.SingleOrDefault();
    }

    virtual public void Delete(long id)
    {
        All.Delete(e => e.Id == id);
    }
}

Tak przygotowane repozytoria możemy użyć bezpośrednio, lub rozszerzać o specyficzne metody które będą w nich ładnie zamykać wszelkie zapytania. Przykładem może być klasa Car i szczególne repozytorium z metodą do wyciągania listy samochodów według daty ich produkcji.

public class Car : IEntity
{
    public long Id { get; set; }
    public string Name { get; set; }
    public int ProductionYear { get; set; }
}

Specyficzne repozytorium dziedziczy po repozytorium generyczny, ale uszczegóławia typ generyczny. Dzięki temu napisane wewnątrz zapytania będą odwoływać się typowo do obiektów klasy Car.

public class CarRepository : EntityRepository<Car>
{
    public IEnumerable<Car> GetCarsByProductionYear(int yearFrom, int yearTo)
    {
        return this.All.Where(c => c.ProductionYear > yearFrom && c.ProductionYear < yearTo);
    }
}

Tak stworzone repozytorium może zostać użyte w warstwie pośredniej lub od razu na warstwie widoku. W ładny sposób udostępnia nam ono logikę związaną ze specyficznymi zapytaniami pozwalając uniknąć niepotrzebnego powtarzania kodu operacji CRUD.

Oczywiście podobnie można zrealizować generyczne CRUDy używając innych niż BLToolkit mostków obiektowo relacyjnych jak na przykład w Entity Framework 4, Linq-To-Sql lub NHibernate.

 

Paczka dla Domu Dziecka…

15 gru

Jako, że święta coraz bliżej postanowiliśmy zrobić wspólnie coś dobrego i w jakiś szczególny sposób udzielić się charytatywnie. Wybór obdarowanej instytucji padł na Dom Dziecka w Orzeszu. Placówka istnieje już od ponad pół wieku i obecnie mieszka tam 30 podopiecznych…

Po krótkiej rozmowie telefonicznej z jedną z wychowawczyń dowiedzieliśmy się jakie są akutalne potrzeby, zrobiliśmy zrzutkę i wyruszyliśmy na zakupy… Do kosza wylądowało nie mało czapek, szalików, rękawiczek i podkolanówek, oraz mega paczka pełna czekoladowych Mikołajów ;)

Świąteczne zakupy

Świąteczne zakupy

Spakowane prezenty dostarczyliśmy na miejsce z Damianem dziś rano. Mamy nadzieję, że wychowankom orzeskiej placówki prezenty się spodobają i że nasza, w sumie dość spontaniczna inicjatywa, okaże się trafiona :) Szczególnie serdecznie pozdrawiam miłe panie które dziś odbierały od nas paczkę…

Zawartość paczki

Zawartość paczki

Oczywiście takie drobne dobre uczynki jak ten polecamy każdemu… jest cała masa instytucji, organizacji i akcji które warto wesprzeć, a świąteczny okres jest do tego bardzo dobrym pretekstem… Jako ekipa B21 wychowankom i pracownikom orzeskiego Domu Dziecka życzymy radosnych i spokojnych świąt…

 
1 Comment

Posted in Zespół

 

Cały widok w jednym stringu…

12 gru

Mvc możemy używać na różne, także mniej zgodne z podstawowymi założeniami jego twórców sposoby. Prześledźmy prosty scenariusz polegający na tworzeniu treści wiadomości e-mail na podstawie szablonu html wypełnianego danymi wygenerowanymi przez kontroler.

Problem ten nie pochodzi w prawdzie z B21, ale rozwiązanie to było mi niezbędne w innym projekcie, który realizowałem. Alternatywą dla niego mogło by być wykorzystanie web clienta pobierającego treść strony z szablonem, ale w tym wypadku nie mogła ona być wystawiona jawnie, więc niezbędne było wewnętrzne jej wyrenderowanie.

Do naszej operacji niezbędny będzie widok, który reprezentować będzie szablon wiadomości e-mail. Wiadomość zawierać będzie dane  e-faktury przesyłanej kupcowi po dokonaniu zakupu w sklepie internetowym:


e-faktura

Kupujący: ${ Model.FullName }
Wartość: ${ Model.TotalAmount }
${ p.Name } - ${ p.Amount }

Do naszego szablonu przygotowujemy odpowiednią, wypełniającą go akcję w kontrolerze:

public ActionResult InvoiceTemplate(int invoiceId)
{
    var invoice = _invoiceService.GetInvoice(invoiceId);
    return PartialView(invoice);
}

Ostatnim krokiem jest właśnie główny cel tego wpisu – pobranie wygenerowanej treści html-a do zmiennej łańcuchowej. Twórcy MVC nie ułatwili w żaden sposób tego zadania. Musimy tutaj postarać się sami, by zasymulować wykonanie się odpowiedniej akcji. W tym celu możemy posiłkować się kodem jak poniżej:

public ActionResult SendInvoice(int invoiceId)
{
     var templateView = PartialView("InvoiceTemplate", invoiceId);
     templateView.ExecuteResult(ControllerContext);

     var writer = new StringWriter();
     var templateViewContext = new ViewContext(ControllerContext, templateView.View, templateView.ViewData, templateView.TempData, writer);

     templateView.View.Render(templateViewContext, writer);

     var invoiceMessage = writer.GetStringBuilder().ToString();

     EmailHelper.Send("Twoja faktura", invoiceMessage");

     return new EmptyResult();
}

Kod ten wyciąga właściwą akcję (linia 3), wykonuje ją (linia 4). Dalej tworzony jest odpowiedni view context (linia 7), który służy do wyrenderowania treści strony do naszego stringwriter’a (linia 9).

W podobny sposób można tez generować np. szablony dokumentów PDF. Jest to o tyle wygodne, że MVC zapewnia nam bardzo elegancki sposób wypełniania szablonów treścią poprzez wykorzystanie przesłanego przez kontroler modelu…

 
3 Comments

Posted in MVC

 

ImapX odbiera wiadomości…

02 gru

Zaczął się grudzień, skończyła się szósta iteracja w naszym projekcie. Dawno nic nie pisaliśmy i warto by to nadrobić… Dziś wpis o jednej z używanych przez nas bibliotek, a mianowicie o ImapX. Ale zacznijmy od początku…

Standardowo .net framework posiada zestaw klas do obsługi protokołu SMTP. Fajnie, nawet bardzo, ale nie tylko wysyłaniem maili żyje człowiek… Komunikacja w jedną stronę to trochę za mało, przydało by się czasem maila ze skrzynki także pobrać… Tutaj zestaw bibliotek jaki oferuje nam Microsoft nieco zawodzi. Ani klient POP3, ani tym bardziej Imap nie posiadają swoich implementacji do użycia w najpiękniejszym z współczesnych frameworków. Z pomocą przybywają nam twórcy darmowej biblioteki ImapX, która okaże się przydatna do obsłużenia drugiego z wymienionych standardów.

Bibliotekę pobrać możemy ze strony jej twórców i już po dołączeniu tego trzydziesto kilobajtowego cacka do naszego projektu możemy rozpocząć odbieranie maili z serwerów pocztowych. W naszym tutorialu postaramy się zawalczyć ze skrzynką w poczcie Google – Gmail.

Na dobry początek waro połączyć się z naszą skrzynką i zalogować. Do tego celu wykorzystamy klasę reprezentującą klienta Imap:

 var client = new ImapX.ImapClient("imap.gmail.com", 993, true);
 client.Connection();

 client.LogIn("login-do-skrzynki", "haslo-do-skrzynki");

Następnym krokiem jest utworzenie obiektów reprezentujących foldery na naszym koncie pocztowym. Do naszych celów wystarczy wyciągnięcie samej tylko skrzynki odbiorczej:

var inbox = client.Folders["INBOX"];

I to już wszystko, co potrzebne do zainicjowania pracy ze skrzynką odbiorczą. Reszta to już operacje które chcemy wykonać, czyli na przykład pobrać znajdujące się na niej wiadomości e-mail odczytując ich treść i przeglądając załączniki:

foreach (var message in inbox.Messages)
{
    message.Process();

    var attachments = message.Attachments;
    var htmlBody = message.HtmlBody;
    var textBody = message.TextBody;
}

Oczywiście na wiadomości możemy wykonywać także inne operacje, np. przenieść ją do folderu ze spamem:

var spam = client.Folders["Spam"];
inbox.MoveMessageToFolder(message, spam);

lub usunąć:

inbox.DeleteMessage(message);

Pamiętamy też, żeby rozłączyć się ze skrzynką po zakończeniu zabawy:

client.Disconnect();

Warto wspomnieć, że oprócz możliwości zarządzania folderami i wiadomościami email potrafi także przeszukiwać skrzynkę. Sama biblioteka wspiera połączenia SSL i jest zgodna z większością popularnych skrzynek Imap. Wygodna, intuicyjna i darmowa.. czego chcieć więcej? Polecam :)

Dodatkowo jeżeli jesteście zainteresowani obsługą maila przez popularniejszy z protokołów, czyli Pop3 warto uzbroić swoją aplikację w bibliotekę OpenPop.NET, której najnowszą wersję wydaną nota bene dzisiaj można pobrać tutaj… Wersji 1.4 tej biblioteki używamy w naszym projekcie i myślę, że gdy tylko przemigrujemy na wersję 2.0 to pojawi się o niej jakaś notka…

 
 

iTextSharp do wypluwania PDF-ów

24 paź

Jedną z ważnych funkcjonalności w zakończonej w czwartek iteracji okazała się możliwość eksportu pewnych danych do pliku PDF zwracanego klientowi. Do tego celu wykorzystaliśmy bibliotekę iTextSharp i przygotowane szablony html dokumentów PDF-owych.

iTextSharp to dotnetowa wersja biblioteki iText wykorzystywanej przez programistów Javy. Co ciekawe do wersji 4.x biblioteka ta była dostępna na licencji MPL lub LGPL, natomiast od wersji oznaczonych piątką licencja zmieniła się na Affero General Public License. Z tej przyczyny z racji komercyjnego zastosowania naszego projektu użyliśmy wersji 4.1.6 dostępnej na sourceforge.

Zastosowanie biblioteki jest raczej proste. W celu konwersji strumienia z szablonem w postaci HTMLa do pliku PDF stworzona została przez nas metoda GenerateFromHtml.

using System.IO;
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;

namespace B21.Core.Utilities.Helpers
{
    public static class PdfGenerator
    {
        public static byte[] GenerateFromHtml(Stream htmlStream)
        {
            var document = new Document(PageSize.A4, 80, 50, 30, 65);

            var stream = new MemoryStream();
            PdfWriter.GetInstance(document, stream);

            document.Open();

            var reader = new StreamReader(htmlStream);
            var elements = HTMLWorker.ParseToList(reader , null);
            foreach (IElement element in elements)
                document.Add(element);

            document.Close();

            return stream.ToArray();
        }
    }
}

Powyższa metoda kolejno tworzy dokument PDF  i strumień który będzie leżał pod naszym dokumentem. Wszelkie zmiany które zostaną dokonane w dokumencie zostaną przepisane do tego strumienia po jego zamknięciu. Dokument otwieramy i wprowadzamy do niego kolejne elementy. Aby listę elementów utworzyć na podstawie dokumentu Html używmy metoody ParseToList z klasy HTMLWorker. Jako parametr podajemy oczywiście stream zawierający plik z szablonem. Ostatnim krokiem jest zamknięcie dokumentu. Tutaj niestety pojawia się problem, ponieważ zamykając dokument przy użyciu metody Close zamykamy tez leżący pod nim strumień. Żeby wyciągnąć dane z zamkniętego już strumienia posługujemy się metodą Stream.ToArray która zwraca tablicę bajtów zawierającą kompletny dokument PDF.

Po konwersji istotne było dla nas również łatwe zwrócenie tak przygotowanego dokumentu użytkownikowi. Do tego celu idealnie posłużyła nam będąca częścią ASP.NET MVC klasa FileContentResult pozwalająca w prosty sposób wypluć plik użytkownikowi z poziomu dowolnej akcji.

public ActionResult ExportToPDF(string templateUrl)
{
    var htmlStream = new WebClient().OpenRead(templateUrl);
    var pdfFile = PdfGenerator.GenerateFromHtml(htmlStream);
    htmlStream.Close();

    var result = new FileContentResult(pdfFile, "application/pdf")
    return result;
}

To tyle… jak widać obsługa PDF pod .net nie musi być trudna, nie wymaga też drogich komercyjnych bibliotek. Mam nadzieję, że wpis okaże się dla was przydatny, pozdrawiam :)

 
2 Comments

Posted in MVC

 

Cicho wszędzie, głucho wszędzie…

15 paź

… co to będzie, co to będzie. A tak całkiem serio, to minął już jakiś czas od kiedy zakończyliśmy iterację drugą. W zasadzie to zaczęliśmy już iterację trzecią i jesteśmy w jej połowie. Skąd więc spadek regularności wpisów?Rozpoczęcie roku akademickiego – to ono jest tutaj chyba głównym tego powodem. Jako, iż czasu nie da się skompresować (a przynajmniej nie znamy na to prostego sposobu), to nasz grafik jest dość napięty, a co za tym idzie często brak już czasu na tworzenie blogowych treści.

W każdym razie poza faktem zaniedbania bloga idzie nam całkiem nieźle. Iteracja trzecia jest dobiegła już połowy, zostało nam do zamknięcia 2500 z 5200 punktów przeznaczonych na obecne zadania, także tempo mamy bardzo równe i chyba coraz lepiej udaje nam się oszacować ilość czasu niezbędną do wykonania zadań (a właściwie to odwrotnie: liczby zadań które możemy wykonać w określonym czasie).

Weekend właśnie się zaczyna, co za tym idzie nareszcie chwila odpoczynku i regeneracji sił przed drugą połową trzeciego etapu naszego projektu. Być może znajdzie się także trochę czasu, żeby coś napisać, np. na temat eksportu html-a do plików PDF przy pomocy biblioteki iTextSharp lub realizacji obsługi POP3 którą zaimplementowaliśmy w kończącym się właśnie tygodniu ;)

 
 

Iteracja druga – zakończona!

30 wrz

Iteracja druga dobiegła już końca wraz z commitem numer 286. Wszystko poszło zgodnie z planem, a nawet ponad normę.

Założyliśmy sobie, ze wykonamy zadania za 4600 punktów, ale praca szła tak gładko, że spokojnie dołożyliśmy sobie jeszcze dwa dodatkowe feature’sy. Ostatecznie wynik w tej iteracji zamknęliśmy na poziomie 5200 punktów i to właśnie za tyle punktów zadania rozwiązywać będziemy w iteracji kolejnej.

Weekend po raz kolejny to czas w którym klient przetestuje aktualną wersję aplikacji i wymyśli nowe zadania które będą wypadkową żądań naprawy znalezionych w trakcie testów bugów i nowych funkcjonalności które będziemy wprowadzać do obecnej wersji systemu.

Iteracja trzecia będzie iteracją dość przełomową, bo według zapowiedzi naszego klienta zaczniemy już realizację kolejnej dużej części aplikacji (równocześnie rozwijając obecną). Dzięki temu lepiej zrozumiemy które części aplikacji powinny być wspólne dla wszystkich modułów, a które odseparowane w oddzielnych area’ch.

Ciekawe czy uda nam się znowu skutecznie zrealizować wszystkie feature’sy które zostaną w poniedziałek przydzielone do kolejnej iteracji? Oby.. sobie i reszcie zespołu życzę powodzenia :)