ASP.NET MVC 1.0 wydane!

W końcu! Na stronach Microsoftu dostępne jest do ściągnięcia ASP.NET MVC 1.0. To doskonała wiadomość dla wszystkich developerów ASP.NET, sam nie mogę się doczekać, aż dobiorę się do świeżutkiego release’a.

W związku z tym, z tego miejsca zapowiadam przepisanie mojego bloga (i udostępnienie źródeł) do ASP.NET MVC 1.0 :) Przy okazji polecam zapoznanie się z fragmentem książki, w którym można znaleźć kompletną instrukcję na temat tego, jak zbudować kompletną aplikację w ASP.NET MVC.

PS. W następnej notce zamieszczę relację z C2C 2009.

ASP.NET MVC – autoryzacja użytkowników dla leniwych

Jeśli chcemy ograniczyć użytkownikom dostęp do różnych funkcjonalności naszej strony napisanej w ASP.NET MVC możemy skorzystać z przydatnych Membership Providerów (tak jak w przykładowej aplikacji MVC), możemy też zainteresować się czymś takim. Również kuszącą opcją jest skorzystanie z (mniej lub bardziej rozbudowanej) Forms Authentication znanej dobrze z „czystego” ASP.NET. Ja skusiłem się na tę ostatnią opcję, gdyż chciałem uzyskać efekt minimalnym nakładem pracy.

Jeśli prowadzicie blog, jedyne czego Wam potrzeba, to ograniczyć „anonimowym” dostęp do pewnych stron i akcji (jak np. dodawanie nowych notek), a dla siebie zatrzymać pełne uprawnienia. W tej sytuacji moje minimalistyczne rozwiązanie wydaje się być rozsądne :) Do rzeczy!

Na początek, w głównym pliku Web.config naszej aplikacji musimy dodać:

<authentication mode=”Forms />”

Aby nasza aplikacja wiedziała, czego od niej chcemy ;) Teraz należałoby stworzyć zwykły widok-formularz, w którym umieścimy pola login i hasło oraz odwołanie do odpowiedniej akcji, na przykład:

<form action=”/Admin/Authenticate/” method=”post”>

To znaczy, że po wciśnięciu przycisku submit uruchomiona zostanie akcja podłączona pod route (to wszystko można ustawić w Global.asax) „http://naszaplikacja.com/Admin/Authenticate/” przekazując przy tym wartości pól Login i Password. Proste, prawda? Teraz należałoby obsłużyć żądanie w kontrolerze. Przykładowa akcja poniżej:

[AcceptVerbs("POST")]
public ActionResult Authenticate(string Login, string Password)
{
if (!ZaawansowaMetodaAutoryzacji())
throw new Exception();
else
{
FormsAuthentication.SetAuthCookie("Admin", false);
return Index();
}
}

Bardzo ważna jest tutaj linia:

FormsAuthentication.SetAuthCookie(„Admin”, false);

To ona spowoduje, że zostaniemy autoryzowani jako użytkownik „Admin”. Drugi parametr („false”) działa jak znane pole „Remember me”, więcej do poczytania tutaj. Fajnie, prawda?

Teraz pozostaje nam już tylko oznaczyć odpowiednie akcje jako chronione. To ważne, chrońcie akcje a nie strony! Odpowiedź czemu zdaje się być oczywista. W dobrze napisanej aplikacji MVC każdy widok (każda strona) renderowana jest po przejściu przez kontroler, a więc przez odpowiednią akcję. Jeśli zabronimy „anonimowym” dostępu do odpowiednich akcji uzyskamy niemal 100% pewność, że nie obejrzą oni danej strony, ani nie wywołają nieprzeznaczonej dla nich metody (np. tworzącej nowy wpis na blogu) :) Jak zabronić dostępu użykownikowi do danej metody (akcji)? To bardzo proste. Wystarczy metodę oznaczyć atrybutem PrincipalPermission. Na przykład:

[PrincipalPermission(SecurityAction.Demand, Name = "Admin")]
[AcceptVerbs("POST")]
public RedirectToRouteResult AddEntry(string Title, string Text)
{
dataContext.AddEntry(Title, Text);
return RedirectToAction("Recent", "Blog");
}

Dzięki temu metoda – wpis może być dodany tylko przez użytkownika „Admin”. W taki sposób oznaczamy wszystkie metody, do których chcemy dodać restrykcje. To tyle! Tym sprytnym sposobem nasza aplikacja jest chroniona w bardzo prosty sposób :)

Tworzymy własny kanał RSS 2.0, czyli kodujemy!

Jeśli prowadzisz stronę z dynamiczną zawartością, to z całą stanowczością potrzebujesz udostępniać ją jako kanał informacyjny. Coraz więcej osób (w tym od niedawna ja ;)) przegląda niusy, wpisy na blogach tylko i wyłącznie używając syndykacji. Ba, myślę nawet, że wiele stron z powodzeniem istniałoby bez jakiegokolwiek layoutu, a jedynie jako feed :) Ale dosyć już spekulacji, do dzieła! :)

Istnieją dwa liczące się standardy kanałów są to Atom i RSS. Polecam zapoznać się z linkami z jakże niezawodnej wikipedii :) W tym miejscu wypadałoby zdecydować się na któryś standard. Ja opiszę przygotowanie feeda w RSS 2.0, ale nic nie stoi na przeszkodzie, żeby zdecydować się na Atom. RSS wydaje mi się nadal być popularniejszym (osobiste odczucie), ale Atom depcze mu po piętach.
Na początek wypadałoby utworzyć stronę o jakiejś wdzięcznej nazwie, np. Feed.aspx. To było proste, teraz jednak przechodzimy w końcu do kodu :) Nie będę się tutaj rozwodził nad specyfikacją gdyż można o niej przeczytać tutaj. Jeśli jesteś leniwy, to wikipedia przedstawia bardzo skrótowy opis i przykład, który jednak nam wystarcza. Oto fragmencik pliku generującego kanał z bloga, którego czytasz:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Feed.aspx.cs" Inherits="hLog.Views.Blog.Feed" %><%Response.ContentType = "application/xml";%><%@ Import Namespace="hLog.Models"%>


Łukasz Sowa - blog programisty .NET
http://lukaszsowa.pl
Feed z najnowszymi notkami
<% foreach(Entry entry in ViewData.Model) { %>

<![CDATA[<% Response.Write(entry.Title); %>]]>
]]>
]]>
]]>

<%} %>


Kod powinien mówić sam za siebie. Są wszystkie wymagane pola , a dodatkowo również , które jest bardzo przydatnym polem. Zwróć uwagę na formatowanie (wymagane pola, kolejność, umiejscowienie), gdyż nawet drobne odstępstwa od reguł mogą powodować poważne błędy. Mój blog, czego tutaj niestety nie widać, pobiera 10 najnowszych postów, a następnie osadza je w znacznikach. Wyjaśnienia wymaga jeszcze tajemnicza CDATA. Otóż podczas parsowania pliku, w wygenerowanej zawartości mogą znaleźć się elementy, które zaburzą układ znaczników, a co za tym idzie – cały nasz Feed wygeneruje się z błędem. Tu właśnie przychodzi z pomocą CDATA. Wszystko co znajduje się pomiędzy znacznikami CDATA jest ignorowane podczas parsowania – czyli nasze dane nie zaburzą znaczników.

No to pozostaje tylko odpalić stronkę i… ups! Kanał wyświetla się zapewne jako plaintext. Nie tego oczekujemy. Podgląd odebranego nagłówka wszystko wyjaśnia – przeglądarka traktuje dane, jako test. Musimy więc odpowiednio oprogramować zdarzenie Page_Load. Kod poniżej:

 protected void Page_Load(object sender, EvenrArgs e)
{
Response.ContentType = "application/xml";
}

Teraz nasza przeglądarka będzie wiedziała (dzięki zmodyfikowanemu nagłówkowi), że odczytuje XML.

Teraz już powinno wszystko działać. Voila! :) Ciesz się swoim własnym kanałem.

PS. To mój pierwszy stricte techniczny tekst, więc liczę na feedback i wyrozumiałość :)

ASP.NET MVC – czego mi tu potrzeba…

Framework MVC Microsoftu jest dopiero w wersji Preview 3. Kiedy należy się spodziewać wersji finalnej? Póki co tj. na obecną chwilę – nie wiadomo (a może ma ktoś jakieś informacje?). Scott Guthrie główny koordynator projektu wraz ze swoim zespołem odwalił już solidny kawał roboty. Wydaje mi się, że wciąż wiele przed nimi.

O leku na to, czego brakuje w ASP.NET MVC pisał Bartek Szafko. Opisany przez niego projekt MVC Contrib nie jest jednak odpowiedzią na moje potrzeby. Dlatego poniżej stworzyłem swój własny wish-list ;)

W ASP.NET MVC Framework chciałbym ujrzeć:
Przyjemne skrypty generujące takie jak choćby scaffold w RoR (generowanie prostych stron CRUD). W środowisku produkcyjnym ich przydatność jest raczej znikoma, jednak myślę, że znajdzie się wiele osób, których taki „ficzer” by uradował i znacząco wspomógł tworzenie prostych aplikacji.
Admin page – pełen, ładny panel „admiński” generowany na podstawie modelu – taki jak w Django. Do zaawansowanych portali raczej się nie nadaje, ale jeśli ktoś pisze system blogowy (tak jak ja), zwykły sklep internetowy czy forum, to oszczędzi mu to wiele pracy.
Ulepszone wyświetlanie widoków – czyli więcej możliwości, jak choćby natywnie wspierane wyświetlanie XML-a (jak ktoś tworzy feed RSS, to wie o czym mówię). O ile dobrze widziałem, to w Preview 3 zajęli się już łatwiejszym generowaniem widoków, głównie jeśli chodzi o przesyłanie ViewData.
Wsparcie dla typowych czynności takich jak na przykład paginacja, internacjonalizacja (hmmm w tym się w ogóle nie orientuję) czy „członkostwo” (jakiś czas temu pisał o tym Bartek Szafko) – nadal wydaje mi się, że autoryzacja nie jest zrobiona w najprostszy sposób.
Hostingi – to nie wina frameworku, ale przydałoby się go już zacząć szerzej reklamować, bo wg. mnie w nim (i w Silverlighcie) leży przyszłość tworzenia stron internetowych w technologiach MS. A hostingów wspierających z tego co wiem, nie ma (czyżby wszyscy się bali instalować wersji Preview?), no może oprócz naszego rodzimego hostedwindows, z którym można się w tej sprawie dogadać :)

Więcej grzechów nie pamiętam… :) Na razie tyle mi przyszło do głowy, ale jestem pewien, że istnieje jeszcze wiele funkcji, które warte byłby zaimplementowania, a o których tu nie wspomniałem. Dlatego dobrze byłoby, gdyby brygada odpowiedzialna za MVC słuchała trochę społeczności i podążała za trafniejszymi wskazówkami. Na razie pracę nad frameworkiem MVC oceniam na bardzo mocną piątkę. Oby tak dalej!

PS. Zapraszam do wpisywania w komentarzach swoich uwag dotyczących MVC :)

Starcie z ASP.NET MVC – akt I

Skończyłem pisać obsługę kanału RSS dla bloga i postanowiłem skrobnąć nieco moich przemyśleń. System blogowy zacząłem pisać tydzień temu i mniej więcej gotowy był po 6 dniach (byłoby szybciej, gdyby nie moje problemy z ASP.NET :)). Wydaje mi się, że to całkiem niezła szybkość produkcji. Dodam, że proces tworzenia nie był zbyt intensywny, a moja znajomość frameworku zbudowana była na lekturze 3 z 4 tutoriali Scotta Guthrie. Fakt, że może przez to cały system nie jest zbyt zaawansowany, ale jest i co najważniejsze – działa! ;)

Oprócz szybkości tworzenia, najważniejszą cechą powstającego dziecka MS jest to, że aplikacje webowy tworzy się dzięki niemu bardzo łatwo i przyjemnie. Naprawdę odczuwałem niesamowitą radość przy klepaniu. Wszystko przychodziło z łatwością, a jeśli nawet czegoś nie wiedziałem, to jedno, dwa spojrzenia w dokumentację (która co prawda jest na razie szczątkowa) i już wszystko było jasne. Kontrolery działają bardzo przewidywalnie (intuicyjnie konfigurowalny routing), a model (który wygenerowałem za pomocą LINQ to SQL – miodzio! korzystałem z tego pierwszy raz i jestem zachwycony!) świetnie z nimi współpracował. Do widoków dane przekazuje się bardzo łatwo – niejawnie, poprzez JEDEN słownik ViewData, bądź po prostu używając silnej typizacji (wymagana jest jedynie zmiana w klasy, z której dziedziczy dany widok. Wszystko to opisane jest tu. Kolejną rzeczą, która zwróciła moją uwagę, to fakt, że w frameworku tym, przynajmniej na pierwszy rzut oka, nie widać „magii”, czyli tego co najbardziej raziło mnie w Ruby on Rails. Nie mam wielkiego doświadczenia z RoR, ale wydaje mi się, że produkt MS niczym nie ustępuje tworowi Davida Heinemeiera Hanssona. Większe doświadczenie mam z Django i stwierdzam, że póki co, ASP.NET MVC brakuje tej „lekkości”, którą ma pythonowy framework. Mam szczerą nadzieję, że to jednak się jeszcze zmieni, przecież dopiero mamy wersję Preview 3, a Django już zdążyło zdobyć doświadczenie na polu frameworków webowych. Kolejną rzeczą, którą można uważać za pewnego rodzaju minus jest brak jakichkolwiek skryptów wspomagających takich jak scaffold w Ruby, czy admin page w Django. Z drugiej strony skrypty te trochę „zaciemniają” oczywistość frameworka, a wszystkie strony tworzone przy ich pomocy są do siebie bardzo podobne, więc przy profesjonalnych cyklach produkcyjnych raczej nie mają zastosowania na większą skalę. Ostatnim minusem jest kiepska integracja z VS. IDE często udziela ostrzeżeń, bądź nawet uważa coś za ewidentny błąd mimo, że kompilator to kompiluje i wszystko działa. Choć może to bardziej wina VS..?

To tyle na pierwszy akt :) Dodam jeszcze, że moje wrażenia opieram na wersji Preview 2, gdyż nie miałem jeszcze okazji zlustrować „trójki”.