sobota, 15 maja 2010

Debugowanie ścieżek ASP.NET MVC: Routes Debugger step by step

errorroad Routing ASP.NET MVC może zrobić sporo zamieszania, jeśli w naszej aplikacji korzystamy z zaawansowanego sterowania pomiędzy kontrolerami i odpowiadającymi im widokami. Dla dużych aplikacji (w obecnej chwili pracuję nad taką, która posiada ponad 120 kontrolerów – i nie ma tu problemów z refaktoryzacją) odpowiednie pokierowanie przepływem żądań to całkiem skomplikowany problem.

Są dwie metody debugowania ścieżek:

  1. Metoda empiryczna, czyli zmieniamy tabelę ścieżek, klikamy F5, po czym zamykamy oczy.
  2. Za pomocą biblioteki RoutesDebug – i tą metodę opiszę za chwilę.

RoutesDebug, czyli

RoutesDebug to pojedyńcza bilblioteka dostępna za darmo, która po dołączeniu do naszej aplikacji MVC oraz odpowiednim skonfigurowaniu (co jest dziecinnie proste) stanie się domyślnym RouteHandlerem.

Czyli zaczynamy

1. Pobieramy bibliotekę RoutesDebug.dll

2. W Visual Studio dodajemy referencję do niej w naszej aplikacji ASP.NET MVC

add_ref

3. Czas na rejestrację naszego nowego RouteHandlera. Przechodzimy do pliku Global.asax.cs i dodajemy jedną (!) linijkę:

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);

//Powstań RoutesDebugerze:
RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);

}

To wszystko. Teraz po uruchomieniu aplikacji powinniśmy ujrzeć stronę na, której prezentowana jest tablica ścieżek w naszej aplikacji.

routesdebug1

Tak naprawdę to jest to nasza konsola testowa :-) Ok, dla przykładu stworzyłem bardzo prostą aplikacyjkę, która zawiera następujące rejestracje scieżek:


public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(null, "Articles/{id}",
new { controller = "Articles", action = "Show" },
new { id = @"\d{1,9}" }
);

routes.MapRoute(null, "Articles/Show/{id}",
new { controller = "Articles", action = "Show" },
new { id = @"\d{1,9}" }
);

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

}

Do kontrolera Articles będziemy dopuszczać jedynie ścieżki które spełniają następujące wymagania:

  • Zawierają numer artykułu, który za pomocą prostego wyrażenia regularnego testowany jest, czy jest liczbą
  • Jeśli nie podamy nazwy metody, to przyjmujemy, że chodzi o metodę Show

Natomiast w konsoli testowej widzimy, że dla wywołania ścieżki: http://localhost/Articles/Show/1 pasujące są wpisy w tablicy:

  • Articles/Show{id}
  • {controller}/{action}/{id}

gdzie jako parametr przekazujemy nasz ID, czyli tutaj liczbę 1, kontroler to ArticlesController, a akcja to Show. Ale w naszym przykładzie zarejestrowałem także scieżkę, w której podanie nazwy akcji jest opcjonalne, przetestujmy więc ją:

http://localhost/Articles/1234

routesdebug3

czyli ścieżka także została rozpoznana, a pusta nazwa akcji została automatycznie uzupełniona przez wywołanie akcji Show, zgodnie z tym co podaliśmy w naszej tablicy routingu. Pozostał ostatni test, czyli test na niepoprawne dane, wpisujemy http://localhsot/Articles/darek –> to nie jest liczba :-)

routesdebug4

ścieżki nie zostały dopasowane, czyli wszystko działa.

piątek, 26 lutego 2010

AutoMapper. A co jeśli w naszym kodzie brak konwencji?

 copier Automapper jest biblioteką ułatwiającą konwersje między dwoma typami. Wykorzystując wspomnianą bibliotekę nie ma już konieczności pisania przydługiego kodu własnych konwerterów. Jak to się dzieje, że Automapper potrafi z typu:

public class BlogPost
{
    public string Title;
    public string Description;
    public string Body;
    public int Level;
    public DateTime CreationDate;
}

wyczarować np. klasę?:

public class BlipPost
{
    public string BlipBody;
    public DateTime DateOfBlip;
}

za pomocą wywołania jednej linijki kodu?:

//konwertujemy obiekt myPostObject z typu źródłowego (BlogPost) do typu docelowego (BlipPost)
Mapper.Map<BlogPost, BlipPost>(myPostObject); 

Otóż domyśla się on - za pomocą ogólnych konwencji nazewniczych - jakiemu typowi z klasy docelowej (BlipPost) będzie odpowiadał typ z klasy źródłowej (BlogPost). Świetnie. Jednak niechaj będzie błogosławiony ten, którego kod konwencji się trzyma. Prosty przykład, dla którego Automapper polegnie na samym wejściu:

public class Osoba
{
    public string Imie;
    public string NazwiskoRodowe;
    public string Nazwisko;
    public DateTime Urodziny;
}

Uwierzcie lub nie, ale Automapper nie da rady sobie zmapować tak prostej klasy na nic – jedynym efektem jego pracy będzie przepiękny wyjątek mapowania.

Wstań, powiedz nie jestem sam…

Można by Automapera o kant … potłuc, gdyby nie umożliwiał poradzenie sobie z podobnymi problemami.

Z pomocą przychodzi własny TypeConverter, który po zaimplementowaniu jednej metody Convert będzie płodził nowe klasy docelowe w sposób jaki mu powiemy.

public class ToBlipPostConverter : ITypeConverter<BlogPost, BlipPost>
{
#region ITypeConverter<BlogPost, BlipPost> Members

public BlipPost Convert(ResolutionContext context)
{
    BlogPost old = context.SourceValue as BlogPost;
    //if old != null
    var blip = new BlipPost();
    blip.Id = old.Id;
    blip.Data = old.DataPosta;
    blip.Level = old.Poziom;
    blip.Body = old.Tresc;
    
    return blip;
}

#endregion
}

Teraz wystarczy jedynie poinformować Automappera do używania naszej klasy konwertera dla podanych typów:

Mapper.CreateMap<BlogPost, BlipPost>().ConvertUsing<ToBlipPostConverter>();

Pisanie własnych konwerterów nieco mija się z celem, jednak sygnalizuję tylko problem na jaki może się natknąć deweloper.

No i tyle. Więcej można przeczytać na stronie projektu: Type Converters.

środa, 17 lutego 2010

Konferencje .NET w najbliższym czasie

26 marzec 2010 (piątek) Poznań 4Developers
4Developers to konferencja dla programistów tworzona przez programistów. Jest to największe przedsięwzięcie tego typu w Polsce – 700 uczestników, 4 równoległe ścieżki i ponad 30 prelegentów. 4Developers to profesjonalna, techniczna konferencja przeznaczona dla developerów i managerów projektów, kadry kierowniczej działów informatycznych, a także wszystkich studentów zainteresowanych programowaniem. Zapraszamy do dyskusji, wymiany doświadczeń i szukania rozwiązań dla wyzwań związanych z tworzeniem i rozwijaniem oprogramowania. 4Developers podzielona jest na cztery niezależne ścieżki związane z technologiami i problemami spotykanymi w nowoczesnych firmach zajmujących się produkcją oprogramowania [źródło 4developers]
- Ja będę tam!

17 kwiecień 2010 (sobota) Warszawa Communities2Communities 2010
C2C to doskonała okazja do spotkania i wysłuchania sesji najwyższej klasy specjalistów z Polski i ze świata, do wymiany doświadczeń i spotkania osób o podobnych zainteresowaniach.Tegoroczna konferencja, podobnie jak ta z ubiegłego roku, obejmuje aż trzy ścieżki tematyczne: przeznaczoną dla profesjonalistów IT, SQL Server oraz .NET. Na każdą ze ścieżek przypada pięć sesji - każda z nich będzie prowadzona na poziomie 300-400 wg skali MSFT, w profesjonalny sposób, przez najlepszych specjalistów, bez zbędnego marketingowego bełkotu. Jak udowodniła zeszłoroczna konferencja, sesje na poszczególnych ścieżkach były na podobnym poziomie jak te prowadzone na konferencjach typu TechEd czy MTS. [Żródło C2c]
- Ja będę tam!

czwartek, 4 lutego 2010

Offtopic: Firefox jest wszędzie

Dziś zwróciłem uwagę na dziwnie wyglądający przycisk Start Windows 7:

1

Pomyślałem sobie: gdzieś już widziałem ten kawałek wystający poza obręb ikony… Szybkie nałożenie podejrzanej ikony (znam jedną ikonę z ogonem):

2

… i jeszcze troszkę wyostrzamy ….

3

I dostaliśmy podpalonego lista. Tylko skąd on tam się wziął?

środa, 20 stycznia 2010

No i Visual Studio 2010 Beta 2 sie popsuło. Samo :-(

UntitledZ tego co pamiętam, to zostało mi jeszcze ok 130 dni testów. Będę żądał zwrotu pieniędzy lub wymiany na nowe.

czwartek, 14 stycznia 2010

Mój ASP.NET MVC stack


Postanowiłem spisać technologie, biblioteki, które używam w pracy z projektami ASP.NET MVC, ewentualnie “nowinki”, które zostały przetestowane w boju, ale ze względu na silną obsadę czekają na lepsze czasy i napewdno niedługo zostaną przeze mnie ponownie użyte. Oto one, zaczynająć od "pierwszego składu":


Architektura

  1. S#arp Architecture: podstawowy stack, który zawiera w sobie wszystko to, co potrzebne jest do stworzenia aplikacji ASP.NET MVC. Korzysta z Castle.Windsor co podmieniam na Ninject.
  2. NHibernate, doskonale wszystkim znany ORM
  3. Linq2SQL, tam gdzie nie ma NHibernate :-)
  4. Fluent Nhibernate biblioteka konfiguracji NHibernate bez konieczności użycia plików XML oparty o konwencję / Fluent Interfaces.
  5. Ninject jako lekki framework DI / IoC.
  6. MVCContrib: projekt rozszerzający standardową funkcjonalność dostępną w gołym ASP.NET MVC
  7. jQuery, jQuery UI, jQuery plugins: biblioteka javascript, zbiór kontrolek JS, chyba każdemu znana.

Poczekalnia

  1. Entity Framework 4, jako zamiennik NHibernate. Zauważyłem, że EF idzie w całkiem fajną, ciekawą stronę umożliwiając MDD, dobrze integruje się z VS. Myślę, że niedługo będzie poważną alternatywą dla NHibernate.
  2. Spark View Engine, jako zamiennik standardowego view engine. Fajne rozwiązanie PartialViews, daje mniejszy bałagan w kodzie widoku.
  3. FubuMVC, framework implementujący wzorzec Front Controller
  4. MVCTurbine: “The whole purpose of MVC Turbine is to speed your MVC development by having the plug-in handle all churn of the runtime and allow you to focus on what your application needs to do, rather than how to do it.”

Coś byście dorzucili? :-)

środa, 13 stycznia 2010

Wzorzec “POST Redirect GET” w ASP.NET MVC

Jednym z największych problemów w aplikacjach internetowych jest podwójne przesłanie danych za pomocą metody POST na szczęście prawidłowo korzystając z mechanizmów ASP.NET MVC można się przed tym obronić – ale o tym za chwilę. Na początek krótkie wyjaśnienie tego w czym cały problem.

Wyobraźmy sobie formularz w którym podajemy: Numer karty kredytowej, datę jej ważności, kwotę w eurogąbkach, którą przelewamy na konto oraz przycisk “Wyślij”, czyli standardowy mechanizm płacenia za płatne treści (taaak wiadomo jakie :-) ) w Internecie.  Formularz w oparciu o metodę POST prześle dane do serwera, gdzie zostanie odpalona jakaś skomplikowana logika, którą nie będziemy się teraz przejmować. Efekt jest taki, że na naszym koncie mamy mniej eurogąbek niż mieliśmy jeszcze minutę temu. Wszystko pięknie, ale po drodze coś mogło pójść nie tak i nie otrzymaliśmy informacji zwrotnej, że przelew się udał. Co gorsza strona może prosić o odświeżenie znanym chyba każdemu użytkownikowi, najczęściej niepoprawnie zaimplementowanych stron, komunikatem:

com

Co zrobi przeciętny użytkownik? Tak: kliknie przycisk Prześlij ponownie. I to kosztowny błąd, bo na jego koncie jest dwa razy mniej eurogąbek.

Problem z formularzami wykorzystującymi metodę POST pojawia się gdy:

  1. Odświeżamy stronę.
  2. Zapisujemy stronę do Zakładek przeglądarki internetowej.

Rozwiązanie: PRG

Wzorzec projektowy PRG polega na:

  1. Przesłaniu formularza w sposób standardowy metodą POST.
  2. Przekierowanie, a ściślej mówiąc, zwrócenie kodu 303 / 302.
  3. Zażądanie załadowania “nowej” strony z użyciem GET.

PRG i ASP.NET MVC

Jak to się powinno zrobić w ASP.NET MVC? Służy do tego: znana chyba każdemu – a niestarty często nie do końca przez wszystkich zrozumiana metoda - RedirectToAction wraz z TempData przechowujący dane pomiędzy żądaniami.

[HttpPost]
public ActionResult Edit(InputData input)
{
if (ModelState.IsValid)
{
//jakas logika...
TempData["ResultMessage"] = "Transfer eurogabek zakonczony!";
return RedirectToAction("index");
}

return View(input);
}




Tak zaimplementowana logika nie spowoduje ponownego przesłania danych przy odświeżeniu strony i to właśnie tak powinny być zaprojektowane formularze korzystające z POST.