Klávesové zkratky na tomto webu - rozšířené Na obsah stránky

Inversion of Control v ASP.NET MVC

10.30 - 24. listopadu 2008 | ASP.NET 2.0

Dneska si ukážeme, jak využít modularity ASP.NET MVC k tomu, abychom mohli snadno integrovat IoC kontejner. Ten pak bude sloužit k tvorbě controllerů a injekci jejich závislostí (dependecy injection). Jako kontejner použijeme Castle Windsor a konfigurační DSL v jazyce Boo – Binsor.

ASP.NET MVC je framework, který si za cíl bere jasné rozdělení odpovědností, modularitu, snadnou rozšiřitelnost a snadnou testovatelnost aplikací nad ním postavených. Což jsou nejpalčivější neduhy „klasického ASP.NET.“

Inversion of Control a Dependency Injection

Inversion of Control (IoC) je tak trochu jiný pohled na programování. Když píšete aplikaci, nepíšete ji jako program, ale jako sadu komponent, kterým „vdechnete život“ pomocí konfiguračního skriptu. Každá komponenta má v systému svoji úlohu, a pokud nám přestane její funkcionalita vyhovovat, lze ji velice snadno nahradit zásahem na jednom místě. Aby to bylo opravdu tak snadné, musí nahrazovaná komponenta splňovat určitý kontrakt – implementovat rozhranní.

Přes tato rozhranní mezi sebou jednotlivé komponenty komunikují, využívají deklarované služby, posílají si data. Jenže, jak mají vědět, kterou komponentu mají za daným rozhranním hledat. Ony to vědět nemusejí, tedy, vlastně by vůbec neměly.

Tak potom kdo? IoC kontejner!

Kontejner je mozkem aplikace. Je to ten jediný, který ví, které komponenty splňují určité kontrakty. Jak se to doví? Při startu kontejner nacpeme komponentami a on nám je později na vyžádání vrací. Dokonce jde tak daleko, že pokud si vyžádáme komponentu, vrátí nám ji včetně všech jejích závislostí a závislosti závislostí. :) Dostanete kompletní graf objektů, které jsou pro danou chvíli potřeba k vykonání dané činnosti a jsou v kontejneru zaregistrované.

Kontejner se tedy stará o dependency injection. Ale není to jediná služba, kterou nám dokáže poskytnout. Jeho další schopností je řídit životnost komponent. Už nikdy více nemusíte psát singletony! Pokud potřebujete singleton, řeknete kontejneru a on se o to postará.

Castle Windsor

Windsor je jedním z takových kontejnerů určený pro dotnet. Jistě najdete spoustu alternativních jako Spring.Net, StructureMap, Unity nebo Ninject. Každý z nich má své výhody, jiné postupy, ale i omezení. Windsor jsem si vybral z několika důvodů:

  1. Je součástí opensource projektu Castle,
  2. tudíž má celkem velkou komunitu uživatelů i vývojářů
  3. a navíc dokáže s dalšími projekty z Castle spolupracovat.
  4. Má širokou škálu způsobů konfigurace: programově, programově přes fluent interface, XML a hlavně pomocí Binsor.

Na toto téma jsem měl menší vnitrofiremní prezentaci. Slajdy z ní si může také prohlédnout.

O Binsoru je ve slajdech také zmínka a jednou už jsem o něm psal.

Integrace s ASP.NET MVC

A konečně se dostávám k tomu, o čem tento spot vlastně je. Jak integrovat Windsor kontejner do naší webové aplikace?

Předpokládám, že máte ASP.NET MVC projekt již ve svém studiu. Pak je nutné mít binárky Windsoru. Pravděpodobně budou stačit ty z RC3. Osobně používám aktuální verzi z trunku. Přidejte si reference na knihovny Castle.Core, Castle.DynamicProxy, Castle.MicroKernel a Castle.Windsor. Pak si budeme muset vytvořit novou továrnu na výrobu controllerů. Vlastně nemusíme, již je součástí MVC Contrib, jen jsem jí trochu zjednodušil.

using System;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.Windsor;

namespace BlogSpots.Infrastructure {
  public class WindsorControllerFactory : IControllerFactory {

    private IWindsorContainer _container;

    public WindsorControllerFactory(IWindsorContainer container) {
      if (container == null) {
        throw new ArgumentNullException("container");
      }
      _container = container;
    }

    public virtual IController CreateController(RequestContext context, string controllerName) {
      controllerName = controllerName.ToLower() + "controller";
      return (IController)_container.Resolve(controllerName);
    }

    public virtual void ReleaseController(IController controller) {
      var disposable = controller as IDisposable;
      if (disposable != null) {
        disposable.Dispose();
      }

      _container.Release(controller);
    }
  }
}

Tato továrna bude fungovat pro Windsor. Ještě ale chci přidat podporu pro Binsor, který je součástí Rhino.Commons. K těm se dostanete přes SVN a spolu s nimi dostanete i aktuální verzi Windsoru. Do projektu si ještě přidáme reference na Rhino.Commons a Rhino.Commons.Binsor. Pak si ještě vytvoříme statický helper pro práci s kontejnerem.

using System;
using System.Web.Mvc;
using Castle.Windsor;
using Rhino.Commons;

namespace BlogSpots.Infrastructure {
  public static class IoC {
    private static readonly IWindsorContainer _container;

    static IoC() {
      _container = new RhinoContainer("windsor.boo");
    }

    public static IWindsorContainer Container {
      get {
        return _container;
      }
    }
  }
}

Tím jsme si nainicializovali kontejner s konfigurací v souboru windsor.boo. Tak, a teď už nám zbývá jen zaregistrovat továrnu pro naši aplikaci a napsat konfigurační skript.

V Global.asax zaregistrujeme továrnu na controllery následovně:

protected void Application_Start() {
  ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(IoC.Container));
}

Do web.config přidáme registraci modulu, který nám umožní nastavit životnost objektu na jeden request:

<system.webServer>
  <modules>
    <add name="PerRequestLifestyle"
      type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.MicroKernel" />
  </modules>
</system.webServer>

Tato registrace je pouze pro IIS 7 integrated mode, je nutné ji ještě přidat do system.web\httpModules, aby vám fungovala i na DevServeru.

Boo na scénu

Tímto máme za sebou vše důležité, pro napsání konfiguračního skriptu a spuštění aplikace. Pokud chcete přidat do VisualStudia podporu pro Boo, ve kterém jsou Binsor konfigurační skripty psané, doporučuju stáhnout si a doinstalovat BooLang Studio.

Pojďme tedy k vytvoření konfiguračního souboru! V rootu aplikace si vytvořte soubor Windsor.boo a nastavíme mu vlastnost Build Action na Content, aby se nám pěkně kopíroval při publikování projektu. Do konfiguráku zadejte následující řádky:

import System.Web.Mvc from System.Web.Mvc

for controller in AllTypesBased of Controller("<nazev assembly MVC projektu>"):
  component controller.Name.ToLower(), controller:
    lifestyle PerWebRequest

Takto jsme do kontejneru zaregistrovali všechny controllery v našem MVC projektu. Postupně můžeme registrovat další komponenty a budovat naší aplikaci, ale o tom zas někdy jindy. Tedy snad…

Autor: Aleš Roubíček | 4x komentováno | Delicious | FriendFeed | Facebook | Linkuj!

Binsor – síla konfigurace

15.18 - 25. srpna 2008 | ASP.NET 2.0

Pokud se dostanete do stádia, kdy potřebujete takovou architekturu, kde je potřeba používat plug-iny třetí strany, kde je potřeba snadno vyměnit komponentu za jinou, přichází ke slovu nějaký druh konfigurace.

Velice často se můžeme setkat s konfigurací komponent v XML. Ať už je to Provider pattern známý z ASP.NET, či vlastní konfigurační sekce, nebo konfigurace Windsor kontejneru, pořád tu máme XML. Jeho ohromnou výhodou je, že se dají systémové komponenty snadno překonfigurovat bez nutnosti celý systém překompilovat. Stačí pouhý restart aplikace. Navíc nástrojů na editaci a validaci XML máme nepočítaně, takže změnu konfigurace zvládne téměř každý.

Velkou nevýhodou XML, je jeho omezené výrazivo. Špatně se v něm píše foreach nebo if. Prostě na složitější konstrukce je potřeba programovací jazyk. A nebo skriptovací!

Boo na scénu

Boo je staticky typovaný objektový jazyk nad CLI (dot net) inspirovaný syntaxí Pythonu. Jeho hlavní silou je metaprogramování. Na úrovni kompilátoru se snadno dají psát makra. Takových maker lze využít k tvorbě přehledných DSL a jednou z takových je i Binsor.

Windsor + Boo = Binsor

Windsor je IoC kontejner na platformě dot net a je součástí opensource projektu Castle. Windsor má v základu dvě možnosti jak konfigurovat komponenty.

  1. Programově na úrovni mikrokernelu.
  2. XML konfigurací.

XML konfigurace je nejčastěji užívanou možností, kvůli výše popsaným výhodám. V trunku se nedávnou objevila i konfigurace pomocí DSL na principu fluent interface přímo v C#. Taková konfigurace je velice pěkná, ale je tu pořád nutnost při každé změně znova celý projekt kompilovat. Proto je tu Binsor, který si bere sílu programovacího jazyka, efektnost XML konfigurace a navíc jednoduchost a přímočarost syntaxe.

Konfigurace komponent

Nejčastější aktivitou s Binsorem nejspíš bude registrace komponent. :)

component 'my_component', IServiceContract, ServiceImplementation:
    # nastavime parametr konstruktoru
    constructorParameter = 10
    # nastavime vlastnost sluzby
    SomeProperty = "Hello Word!"

Kód je v celku jednoduchý. Na prvním řádku začínamé klíčovým slovem component, které říká, že registrujeme komponentu. Prvním parametrem je název komponenty, přes který se na ní můžeme odkazovat. Druhý parametr je rozhranní služby a třetí je konkrétní implementace, která bude při rozpoznání kontejnerem vrácena, např. IoC.Container.Resolve<IServiceContract>(). Za dvojtečkou pokračuje výčet nastavovaných vlastností a parametrů. Můžeme takto nastavovat i speciální vlastnost ovlivňující životnost objektu.

component HttpRequest:
    lifestyle Singleton

Všimněte si, že se ani nemusí při registraci uvádět referenční název nebo abstraktní typ. Může se klidně rovnou registrovat typ konkrétní, který se bude v tomto případě chovat jako singleton. Takovéto ukázky jsou fešné, ale nic, co bychom nezvládli pomocí XML. Pojďme trochu dál.

for type in AllTypesBased of Controller("MyApplication.Web"):
    component type

Tento kód zaregistruje všechny controllery (třídy, které jsou potomky třídy Controller) z assembly MyApplication.Web. Krom generické metody AllTypesBased, je tu ještě generická metoda AllTypesWithAttribute a negenerická AllTypes. Všechny mají jako parametr název assembly, jejíž typy procházejí.

Facility

Neméně důležitou součástí konfigurace jsou facility, které dodávají kontejneru nové možnosti a zapouzdřují větší sady komponent do logických jednotek. Pro ukázku konfigurace ActiveRecord komponent pomocí Binsoru:

facility ActiveRecordFacility:
    configuration:
        @isWeb = true, isDebug = true
        assemblies = [ Assembly.Load("MyApplication.Entities") ]
        config(keyvalues, item: add):
            show_sql = true
            command_timeout = 5000
            cache.foo.use_query_cache = false
            dialect = 'NHibernate.Dialect.MsSql2005Dialect'
            connection.provider = 'NHibernate.Connection.DriverConnectionProvider'
            connection.driver_class = 'NHibernate.Driver.SqlClientDriver'
            connection.connection_string = 'connectionString1'

Shrnutí

Osobně se mi možnosti konfigurace přes Binsor velice líbí, ale je celkem možné, že ne každému to může vyhovovat. Pokud ale používáte Windsor a přijde vám XML konfigurace nepřehledná, je toto možná cesta, jak z toho ven. Pokud chcete nějaké lepší příklady, doporučuju si stáhnout SVN repository https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-commons a projít si testy. Jako editor se mi osvědčil SharpDevelop, který má podporu pro Boo přímo v základu, nebo doinstalovat BooLang Studio do Visual Studia.

Tagy: , ,

Autor: Aleš Roubíček | 2x komentováno | Delicious | FriendFeed | Facebook | Linkuj!

Active Record vs. Repository pattern

12.38 - 21. května 2008 | ASP.NET 2.0

Dnes se podíváme na dva návrhové vzory z oblasti přístupu k datům, které používají zcela odlišnou filosofii, ale nakonec si ukážeme, že jejich kombinací, můžeme získat celkem zajímavé výsledky.

Active Record

Návrhový vzor Active Record staví na předpokladu, že základem aplikace je databázový model a od něj se vše odvíjí. Každý řádek tabulky je reprezentován konkrétní instancí objektu. Většinou je takový objekt odvozen od bázové třídy, která implementuje potřebné rozhranní pro persistenci objektu – typicky CRUD metody.

Diagram vzoru ActiveRecord

Tento vzor se hojně využívá v různých ORM frameworcích. Je součástí dnes velmi módních frameworků Ruby on Rails, django nebo Castle, které na něm stavějí svůj datový model a díky velice snadnému mapování dokážete napsat (vygenerovat) kostru databázové aplikace během několika málo minut.

Pro velice jednoduché aplikace může být tento vzor, díky své jednoduchosti, vhodný. Jenže porušuje několik pravidel dobrého objektového návrhu (persistence ignorance, single responsibility, pevně daná bázová třída, atd.).

Repository

Návrhový vzor Repository je základním kamenem doménou řízeného návrhu. Model aplikace nemá ponětí o tom, jakým způsobem je persistován. O to se stará právě Repository. Navíc díky tomu, že se o persistenci stará cizí objekt, stačí nám znát pouze jeho rozhranní a v případě potřeby ho snadno nahradit jiným.

Diagram vzoru Repository

Kombinace

Teď zabrousím do konkrétnějších implementací a to do ActiveRecord z projektu Castle. Tako konkrétní implementace je postavená na běhovém prostření dotnet a jako svůj základ používá ORM nástroj NHibernate.

Nejpřímější cesta jak s ním pracovat, je podědit třídu z bázové třídy ActiveRecordBase a označit ji a její vlastnosti patřičnými atributy:

[ActiveRecord]
public class User : ActiveRecordBase<User> {
  [PrimaryKey] public int Id { get; set; }
  [Property] public string Name { get; set; }
  [Property] public string Email { get; set; }
  [Property] public string Login { get; set; }
  [Property] public string Password { get; set; }
}

A můžeme pracovat. Autoři si však byli vědomi toho, že vzor Active Record nemusí vyhovovat všem a přidali statickou třídu ActiveRecordMediator, který dokáže posloužit jako základ pro Repository. Třída pak nemusí dědit z ActiveRecordBase:

[ActiveRecord]
public class User {
  [PrimaryKey] public int Id { get; set; }
  [Property] public string Name { get; set; }
  [Property] public string Email { get; set; }
  [Property] public string Login { get; set; }
  [Property] public string Password { get; set; }
}

public class UsersRepository : IRepository<User> {
  public User Load(int id) {
    return ActiveRecordMediator<User>.FindByPrimaryKey(id);
  }
  public void Save(User obj) {
    ActiveRecordMediator<User>.Save(obj);
  }
  public void Delete(User  obj) {
    ActiveRecordMediator<User>.Delete(obj);
  }
}

To už je o něco lepší, ale stále máme v aplikačním modelu silnou vazbu na datový model. Můžeme se posunout o level dál a zkombinovat oba vzory tak, abychom z nich vytěžili co nejvíce. Základní myšlenkou je to, že v aplikaci budeme mít jak datový model, tak doménový. Datový model se bude pomocí Active Record starat o persistenci a Repository poslouží k transformaci doménového modelu na ten datový.

Něco podobného můžete najít v seriálu, který píše Rob Conery, kde používá zjednodušenou Repository, IQueryable jako filtry a LINQ2SQL jako datový model. Velice zajímavé, doporučuji ke shlédnutí.

Tagy: , ,

Autor: Aleš Roubíček | 3x komentováno | Delicious | FriendFeed | Facebook | Linkuj!

MVC na ASP.NET – Testování jednotek

16.15 - 1. prosince 2007 | Webdesign

Již delší dobu jsem chtěl napsat článek o tom, proč je MonoRail lepší, když chceme, aby se projekt dal testovat. Jenže vždycky nějak nebyl čas. Navíc se blíží vypuštění ASP.NET MVC, takže nakonec z toho bude trošku obecnější pojednání než jsem původně plánoval.

WebForms testování

Než si ukážeme jak snadné je testovat MVC, nejprve si povíme, že i WebForms se dají testovat. Ano, ale vyžaduje to větší kázeň a víc práce. :) Většinou stejně použijete MVP pattern nebo jeho blízké příbuzné. Pokud tedy nechcete psát testy, které simulují livecycle stránky a dekódují ViewState. (Ano, dotahuju to ad absurdum, ale i tak to může vypadat.)

Aby se tedy kód dal snadno testovat, měl by se co nejvíce oddělit od stránky.

Klasickým modelem tedy je využití MVP vzoru, kdy aspx stránka obsahuje pouze logiku pro prezentaci dat a implementuje rozhranní View, přes které komunikuje s Presenterem. Díky tomu, že Presenter obsahuje téměř veškerou logiku, je ideálním místem pro zacílení našich testů. Pro účely testů pak implementujeme stub nebo mock rozhranní view. Na něm pak sledujeme jak ho Presenter ovlivňuje.

Předchozí diagram ukazuj, že Presenter zná rozhranní View. Stránka, která toto rozhranní implementuje, se však musí postarat o to, aby byl presenter ve správnou chvíli zavolán. Možný scénář zachycuje ukázka kódu.

public class BlogViewPage : System.Web.UI.Page, IBlogView {
  BlogPresenter presenter;

  protected void Page_Init(object sender, EventArgs e) {
    presenter = new BlogPresenter(this); // injekce View
  }

  protected void Page_Load(object sender, EventArgs e) {
    presenter.LoadArticles();
  }

  // implementace IBlogView ...
}

Na to, že to stránka udělá správně, se už musíme spolehnout. Otestovat i takto jednoduchý kód, je už trošku náročnější práce…

MVC testování

MVC frameworky jako MonoRail nebo ASP.NET MVC, přicházejí s podobným schématem by default. V podstatě nás přímo nutí psát web tak, aby se dal lépe testovat. :) Nebudu přehánět, když řeknu, že ASP.NET MVC byl psán se zřetelí na velice snadné testování a obsahuje i sadu mock objektů (např. pro HttpContext). MonoRail dokonce přináší i Fixtures a Asserty pro snadnější testování – bohužel jsou psané pouze pro NUnit, který nepoužívám.

Tento diagram se od předchozího mírně liší. Controller např. netuší jaké má View rozhranní, proto s ním nikterak nepracuje. Prostě zavolá RenderView(*název*, *objekt s daty*) a spoléhá se na ViewFactory že všechno zařídí. Navíc stránka do poslední chvíle netuší, jestli něco bude dělat. Tady totiž proces zpracování začíná u routingu, který vybere správný controller, viz předchozí díl.

Dostáváme se i k lepšímu objektovému návrhu, kde každá třída je zodpovědná za provedení pouze jednoho úkolu (stránka v MVP těch úkolů řeší hned několik). To se opět lépe testuje. Máme sadu několika komponent s jednoduchými závislostmi a každá má na starosti pouze jednu část z procesu.

Pro dnešek to tady ukrouhnu. Bude-li nějaké příště, ukážeme si nějaké praktické ukázky. Možná :)

Související

Autor: Aleš Roubíček | Zatím bez komentáře | Delicious | FriendFeed | Facebook | Linkuj!

Problem ActiveRecord se SQL CE

20.17 - 27. listopadu 2007 | ASP.NET 2.0

Píšu takovou malou aplikaci, která používá SQL Compact Edition pro ukládání dat a Castle ActiveRecord jako persistenční vrstvu. Očekával jsem, bezproblémové použití, ale chyba lávky. To bych přišel o námět na tenhle spot.

Napoprvé jsem chtěl využít služeb LINQ to SQL, ale ten si s SQL CE moc nerozumí (tj. vůbec). Tak jsem tedy sáhl po ActiveRecord o kterém jsem četl, že se SQL CE umí (díky NHibernatu). Přidal jsem DB do projektu, nastavil konfiguraci následujícně:

<activerecord>
  <config>
    <add key="hibernate.dialect"
         value="NHibernate.Dialect.MsSqlCeDialect" />
    <add key="hibernate.connection.driver_class"
         value="NHibernate.Driver.SqlServerCeDriver" />
    <add key="hibernate.connection.provider"
         value="NHibernate.Connection.DriverConnectionProvider" />
    <add key="hibernate.connection.connection_string"
         value="Data Source=DbFile.sdf;" />
  </config>
</activerecord>

Spustím testy. Nic, spadlo to na výjimce, že NHibernate nemůže vytvořit Driver pro SQL CE. Po chvilce hledání jsem našel, že se musí u reference na Syste.Data.SqlServerCe nastavit vlastnost Copy Local na True a to i u testovacího projektu!

Tak jsem zas o něco chytřejší :)

Autor: Aleš Roubíček | 2x komentováno | Delicious | FriendFeed | Facebook | Linkuj!

Castle RC3 a Microsoft MVC

07.48 - 9. října 2007 | Webdesign

Vůbec jsem si toho nevšiml, ale RC3 verze Castle je již několik týdnů venku. Stáhnout si jí můžete ze SourceForge.

Další zajímavou zprávou je. že Microsoft pracuje na vlastním ASP.NET MVC frameworku, který bude umožňovat plnou testovatelnost, IoC kontejnery, ASPX jako view bez ViewState a Page lifecyklu a spoustu zajímavých vychytávek využívajících generika a nové možnosti C#3. První CTP by se měla objevit do konce roku a releas někdy na jaře roku příštího. Release by měl být podobný jako AJAX Extensions, časem se pak zařadí přímo do .net frameworku.

Zajímavý je pohled vývojářů MonoRailu. Vítají zdravou konkurenci a podle všeho se budou snažit využít všech výhod ASP.NET MVC a MonoRail budovat dále nad ním.

Související

Autor: Aleš Roubíček | Zatím bez komentáře | Delicious | FriendFeed | Facebook | Linkuj!

MonoRail – Instalace

13.27 - 3. září 2007 | ASP.NET 2.0

Na jednu zásadní věc jsem v prvním díle zapomněl – tedy spíš jsem s ní počítal, ale nakonec jsem jí nedal prostor – a tou je instalace.

Existují, přinejmenším, tři možné způsoby získání MonoRailu, potažmo celého projektu Castle. Buďto si stáhnete instalátor (aktuálně verze RC2 RC3, která vyšla někdy koncem minulého roku koncem září), nebo využijete služeb build serveru a stáhnete si poslední stabilní build vývojové verze. Třetí možností je získat aktuální zdrojové kódy ze Subversion a celý projekt sestavit s NAntem.

Instalátor je klasický balíček MSI, který za vás udělá špinavou práci:

  • Nahraje všechny potřebné soubory na disk,
  • Zaregistruje potřebné knihovny do GAC,
  • Zaregistruje na lokálním IIS příponu .rails pro ISAPI filtr ASP.NET,
  • Přidá dva nové projekty (MonoRail a ActiveRecord) a průvodce do Visual Studia (2003, 2005 SP1).

Nevýhodou tohoto řešení, je neaktuálnost celého kompletu, na druhou stranu je výhodou, že nám zamete cestičku a můžeme rovnou vyvíjet.

Z build serveru si můžete stáhnout aktuální stabilní verzi knihoven v ZIP balíčku. Je to mužnost oba postupy zkombinovat, ale možná se vyplatí používat prozatím RC2 verzi a počkat si na verzi RC3, která by již brzy měla spatřit světlo světa.

Update

14 dní po vydání toho článku spatřila světlo světa RC3 verze Castle, takže některé výše zmíněné věty ztratili na aktuálnosti. :)

Založení projektu

Předpokládám, že jsme si Castle nainstalovali pomoci MSI balíčku. Máme Visual Studio 2005 ve verzi Standard a vyšší s nainstalovaným WebApplication projektem nebo SP1. Dáme vytvořit nový projekt a zobrazí se nám obrazovka podobná té následující:

Nový projekt

Červeně označené jsou nově přidané projekty

  1. Knihovna s podporou persistence pomocí ActiveRecord
  2. Webová aplikace MonoRail

Pro začátek si vystačíme pouze s MonoRail projektem, protože i ten má podporu pro ActiveRecord a tak můžeme model později přesunout do samostatné knihovny. Takže dáme vytvořit nový MonoRail projekt. Spustí se nám jednoduchý průvodce, který nám přednastaví projekt podle našich potřeb.

V prvním kroku si vybereme, který View Engine chceme používat (samozřejmě jde změnit později v konfiguraci), jestli chceme zapnout integraci s Windsor kontejnerem a jestli zapnout podporu pro routing.

Ve druhém kroku se nás průvodce zeptá, jestli chceme vytvořit také testovací projekt (NUnit s podporou pro testování MonoRail). Samozřejmě chceme :) Průvodce nám vytvoří základní strukturu projektu podobnou následujícímu obrázku.

Struktura projektu

V takovéto kostře si můžete vyzkoušet ukázky z předešlých dílů, snad by měly fungovat…

Autor: Aleš Roubíček | Zatím bez komentáře | Delicious | FriendFeed | Facebook | Linkuj!

Jak funguje MonoRail

13.20 - 17. srpna 2007 | ASP.NET 2.0

Po letmém seznámení s frameworkem MonoRail (MR) je tu první část slibovaného seriálu. V dnešním díle se ponoříme do technických principů frameworku.

Základem MR je klasický IHttpHandler známý z ASP.NET, který se stará o zpracování požadavků přicházejících na server. Ve výchozím stavu zpracovává požadavky s příponou .rails, ale protože tato není na většině hostingů nastavena na ISAPI filtr ASP.NET, dá se nastavit zpracování přípony jiné (často ashx), která je webovému serveru známá a je spojená s ASP.NET filtrem.

Handler rozparsuje adresu a snaží se najít vhodný Controller a jeho metodu, která požadavek zpracuje a předá data na patřičný View. Vypadá to asi následovně. Na handler přijde požadavek ve tvaru /home/index.rails, handler se pokusí vyhledat třídu HomeController, která dědí ze třídy Controller, a u ní metodu Index(). Takže controller pro tento požadavek by vypadal asi následovně:

public class HomeControler : Controller {
  public void Index()  {
    PropertyBag["hello"] = "Pozdrav z jednokolejky";
  }
}

Takový controller by se měl nacházet v projektu ve složce controllers. Vlastnost PropertyBag je slovník (asociativní pole), který předává data z controlleru na view. Aby se nám to celé mohlo někde zobrazit, potřebujeme ještě tedy view. Ve složce /views/home/ si vytvoříme soubor index.brail (Brail je jedním z ViewEnginů) do kterého zadáme:

<html>
  <head>
    <title>Pozdrav</title>
  </head>
  <body>
    <h1>${hello}</h1>
  </body>
</html>

Řetězec ${hello} bude na výstupu nahrazen textem z PropertyBagu. Dolar složené závorky totiž prochází lokální proměnné a snaží se z nich získat hodnotu. Pokud taková proměnná neexistuje zavolá se metoda GetParametr, která projde kolekce PropertyBag, Flash, Request apod. a snaží se v nich nalézt klíč, kterým je text mezi závorkami. Hodnota je pak vypsána namísto dolarové funkce. :) Dolarová funkce je takový shortcut pro tento zápis: <?brail output hello ?> což je obdoba <?php echo $hello; ?> v PHP nebo <%= hello %> v ASP.

Celá skládačka do sebe zapadne, když do prohlížeče zadáme adresu http://server/home/index.rails. Díky příponě rails se požadavek předá Handleru MonoRail. Ten rozparsuje adresu a snaží se najít třídu HomeController, kterou jsme vytvořili, takže success. V této třídě hledá metodu Index, tu máme taky, další bod k dobru. Tato metoda nám nastaví v PropertyBagu hello na hodnotu „Pozdrav z jednokolejky“. Dále handler hledá vhodné view, které jsme také vytvořili. Předá mu Context, zpracuje se šablona a nakonec bude do prohlížeče odesláno HTML.

<html>
  <head>
    <title>Pozdrav</title>
  </head>
  <body>
    <h1>Pozdrav z jednokolejky</h1>
  </body>
</html>

Pro dnešek vše.

Související

Autor: Aleš Roubíček | 4x komentováno | Delicious | FriendFeed | Facebook | Linkuj!

Začínáme s jednokolejkou

16.10 - 14. srpna 2007 | ASP.NET 2.0

Jedním z fenoménů poslední doby ve webovém vývoji jsou bezesporu Ruby on Rails (RoR). Framework určený k RAD Agile vývoji používající objektový přístup a postavený na návrhových vzorech jako je MVC nebo Active Record. Framework je určený pro jazyk či platformu Ruby, to je jeho výhoda i omezení zároveň. Málokdo se má chuť nebo čas se po nocích učit novým jazykům a stávat se vícenásobným robotem.

RoR není rozhodně jediným projektem s podobnou filosofií. My dotneťáci máme krom WebForms, které se snaží přihnout webový vývoj desktopovým zvyklostem (událostmi řízený, stavový), podobný framework, který je navíc opensource. Tento framework se jmenuje MonoRail a oněm bude následující článek a možná i mini seriálek :)

MonoRail

Z názvu by se mohlo zdát, že má projekt něco společného s Monem, opensource implementací dotnetu, ale není tomu tak, krom toho, že MonoRail běží i na Monu 1.1. MonoRail je součást opensource projeku Castle, který si klade za cíl RAD v Enterprise prostředí. Jeho součástí jsou frameworky ActiveRecord (ORM Persistence layer postavený nad NHibernate), Windsor container (Inversion of Control), DynamicProxy (vytváří Proxy třídy z Interfejsů) a právě MonoRail. Všechny frameworky umějí pracovat samostatně, ale jejich největší síla je v jejich spolupráci.

Co je tedy MonoRail? Je to MVC framework inspirovaný ActionPackem běžící na platformně dotnet. Je to náhrada ASP.NET WebForms, ale ty mohou sloužit jako ViewEngine, nebo běžet v jedné aplikaci s MonoRails vedle sebe. Dalšími ViewEnginy jsou NVelocity (port Velocity pod dotnet) nebo Brail (Views jsou psaná v jazyce Boo, což je skriptovací Python like jazyk pro dotnet). Preferovanější je asi NVelocity, ale vývoj Brailu je živější, a WebForms se pro změnu skoro nepoužívají (kvůli PageLife cyklu, který v MonoRailu neexistuje). MonoRail se vám může oproti ASP.NET zdát oldskůlovější, ale opak je pravdou. MonoRail přináší zjednodušení, vrací se k webovému vývoji (bezestavový, Request/Response), staví na osvědčených metodách a zrychluje celý vývoj. Konec řečí, pojďme na věc :)

Model

Model obecně slouží jako zdroj/zpracovávač dat aplikace. Podle toho, jak je vaše aplikace složitá, je bohatý váš model :). Zpravidla se jedná o Domain Model, Business logiku, nebo cokoli jiného, co má na starosti ověřování obchodních pravidel, persistenci a získávání dat. Pro jednoduchost stačí vygenerovat Entity podle DB schématu pomocí ActiveRecord Generatoru nebo naopak vytvořit model a z něj vygenerovat schema.

[ActiveRecord]
public class User : ActiveRecordBase {
  [PrimaryKey] public int Id { get; set; }
  [Property] public string Name { get; set; }
  ...
}

Pro zjednodušení napsáno v C# 3.0 :) ActiveRecord plně využívá atributů k popisu schematu. Dědění třídy ActiveRecordBase není nutností, pro začátek stačí vědět, že nám přidává k entitě spoustu metod pro databázový přístup. Vhodnější pravděpodobně bude využít interface IRepository<T> z projektu Rhino.Commons, který využívá Repository pattern.

View

View jsou obvykle soubory obsahující kusy HTML kódu a prezentační logiky. K zapouzdření prezentační logiky lze využít tzv. View komponent (obdoba UserControls, ale většinou mnohem obecnější). Existují tu i layouty, což je obdoba MasterPages.

<html>
  <head>
    <title>Layout</title>
  </head>
  <body>
    ${ChildOutput}
    <p class="footer">Společná patička.</p>
  </body>
</html>

Takto vypadá velice zjednodušený layout. ${ChildOutput} bude nahrazen obsahem jednotlivých view.

Controler

Kontroler spojuje svět View se světem Modelu. Řídí činnost view mění stavy Modelu. Je to to, co dělá aplikaci aplikací.

[Scaffolding(typeof(User))]
public class UsersController : Controller {
}

Teď když zadáme něco jako http://localhost:12345/users/new.rails tak dostaneme formulář pro zadávání nových uživatelů. (V případě, že doimplementujeme třídu User, aby měla všechny potřebné vlastnosti).

Pro dnešek bych tedy ukončil první představovací článek a v příštích spotech bychom se mohli podívat na tuto zajímavou technologii trošku blíž…

Autor: Aleš Roubíček | Zatím bez komentáře | Delicious | FriendFeed | Facebook | Linkuj!