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

Model binders v ASP.NET MVC

20.15 - 13. prosince 2008 | ASP.NET 2.0

Jednou z pěkných vlastností ASP.NET MVC je, že data která posíláte akci, můžete v kódu získávat přes silně typové parametry metody (akce). Pokud dostatečně dodržujete dané konvence, můžete takto získat i třeba komplexní typy.

To je zařízeno něčím, co se jmenuje model binders. Základem je DefaultModelBinder, který implementuje rozhranní IModelBinder. Dále pak atributy BindAttribute a jeho bratříček k psaní vlastních atributů CustomModelBinderAttribute a v neposlední řadě metody řadiče UpdateModel a TryUpdateModel.

O tom jak používat DefaultModelBinder, si můžete přečíst třeba u ScottaGu. Já bych se spíš chtěl zaměřit na možnosti rozšíření, které nám infrastruktura model binders přináší.

Velkou slabinou konvenčního DefaultModelBinderu je, že ve view musíte dodržovat jmenné konvence vašeho modelu. Sice to může přinést spoustu benefitů, ale i problémů.

Možnosti

Možností, jak bindery používat, je mnoho. Můžete si třeba bindovat z AppSettings nebo z třeba z cookie. I to je pomocí model binders možné. Pojďme se ale podívat na to, jak bindovat váš model na data odeslaná z view s odlišnou jmennou konvencí…

Základy

Vlastní bindery můžeme vytvořit tak, že implementuje rozhraní IModelBinder. Hotovou implementaci pak musíme zaregistrovat při startu aplikace. Pro ukázku si uděláme velice jednoduchý příklad načítání adresy z FormsCollection. Mějme datovou třídu adresa:

public class Address {
    public string Street { get; set; }
    public string StreetNumber { get; set; }
    public string Town { get; set; }
    public string PostalCode { get; set; }
}

K ní si vytvoříme model binder:

public class AddressBinder : IModelBinder {
  public ModelBinderResult BindModel(ModelBindingContext bindingContext) {
    var address = new Address {
      Street = bindingContext.HttpContext.Request["address_street"].Trim(),
      StreetNumber = bindingContext.HttpContext.Request["address_street_number"].Trim(),
      PostalCode = bindingContext.HttpContext.Request["address_postal_code"].Trim(),
      Town = bindingContext.HttpContext.Request["address_town"].Trim(),
    };

    return new ModelBinderResult(address);
  }
}

Který nakonec zaregistrujeme v Global.asax:

protected void Application_Start() {
  ModelBinders.Binders[typeof(Address)] = new AddressBinder();
}

Když teď akci předáme parametr typu Address, bude automaticky vázán pomocí AddressBinderu. Stejně tak, použijeme-li metodu UpdateModel. V některých scénářích zjistíte, že výše uvedený binder, není úplně skvělý, ba co víc, že je v podstatě dost k ničemu. Navíc taky přijdete na to, že když váš model bude trochu bohatší, tak se váš Global.asax pěkně natáhne, navíc pokud budou mít vaše bindery závislosti na jiných službách, začne v tom být pěkný bordel…

Binsor na scénu

Minule jsme si ukázali, jak propojit ASP.NET MVC s IoC kontejnerem a dnes ho využijeme a trochu si ulehčíme práci… Jak jsem již psal, všechny model bindery implementují rozhranní IModelBinder a toho můžeme využít pro jejich registraci do kontejneru, přidáním následujících řádků do souboru Windsor.boo:

for binder in AllTypesBased of IModelBinder("<nazev assembly s Model Bindery>"):
  component binder.Name.ToLower(), IModelBinder, binder

Máme je zaregistrované v kontejneru, ale potřeby psát něco do Global.asax jsme se nezbavili. To je pravda, ale vzápětí to napravíme. Budeme ještě potřebovat generickou bázovou třídu. Proč gerenerickou? No, je v tom takovej fígl – ten prozradím až za chvíli. :) Teď k věci:

public abstract class ModelBinderBase<T> : IModelBinder {
  public Type ModelType {
    get { return typeof(T); }
  }
  public abstract ModelBinderResult BindModel(ModelBindingContext bindingContext);
}

V podstatě jsme rozšířili rozhraní IModelBinder o znalost typu datového objektu se kterým pracuje. Proč? Vzpomeňte si na registraci binderu, kde je klíčem ve slovníku binderů typ datového objektu. Ano, to je on!

Jěště trochu poupravíme náš AddressBinder:

public class AddressBinder : ModelBinderBase<Address> {
  public override ModelBinderResult BindModel(ModelBindingContext bindingContext) {
    var address = new Address {
      Street = bindingContext.HttpContext.Request["address_street"].Trim(),
      StreetNumber = bindingContext.HttpContext.Request["address_street_number"].Trim(),
      PostalCode = bindingContext.HttpContext.Request["address_postal_code"].Trim(),
      Town = bindingContext.HttpContext.Request["address_town"].Trim(),
    };

    return new ModelBinderResult(address);
  }
}

Pořád tu zůstává ta nepěkná závislost na HttpRequestu, je snadno řešitelná, ale našemu příkladu nevadí a vypořádáme se s ní někdy jindy… Takže vraťme se zase k Windsor.boo a na jeho konec přidejme následující řádky:

for modelBinder as duck in IoC.Container.ResolveAll of IModelBinder():
  ModelBinders.Binders[modelBinder.ModelType] = modelBinder

Upozorňuji, že tyto řádky musí být až na konci souboru. Musí se volat, až po tom, co se zaregistrují všechny komponenty, protože tady si vyzvedáváme již hotové bindery z kontejneru a registrujeme je do ASP.NET MVC.

Možná jste si povšimli formulky as duck. Boo je staticky typovaný jazyk, stejně jako C#, jen využívá implicitního typování. V tomto případě nám generická metoda ResolveAll vrací hotové instance, které implementují rozhranní IModelBinder a taky mají tento silný typ. A toto rozhraní neví nic o tom s jakým typem modelu je svázáno.

Naštěstí Boo podporuje duck typing, což nám přidává tak trochu dynamičnost – pozdní vazbu. Já vím, že všechny moje bindery dědí z bázové třídy, která má vlastnost ModelType a s použítím as duck jí můžu zavolat. Tohle je vlastnost, kterou bude C# umět až ve verzi 4.0, do té doby je v něm toto velice těžko řešitelné (osobně jsem se o to ani nepokoušel, ale nejspíš nějak přes reflexi by to jít mělo).

Tím jsme se zbavili nutnosti registrovat každý model binder zvlášť.

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

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 | Zatím bez komentáře | Delicious | FriendFeed | Facebook | Linkuj!

Proč jsou statické helpery zlo?

10.53 - 22. listopadu 2008 | ASP.NET 2.0

Minulý týden psal Arthur spotík o takovém tom víkendovém programování, ve kterém šlo hlavně o to, že přešel na Vistu, vytvořil si gadget pro přehrávání ČRo a taky editor hosts souboru. Napsal ho v C# a zmínil se o tom, že použil techniku, se kterou nejsem s to…

Zkrátka podědil si generickou Dictionary<TKey, TValue> a rozšířil ji o serializaci. Dictionary není serializovatelná. Je to dáno jak její generickou povahou (constraints pro atributy neexistují), tak tím, že sídlí v knihovně, která nesmí mít závislost na jiné, která serializaci zajišťuje.

public class SerializableDictionary<TKey, TValue>
  : Dictionary<TKey, TValue>, ISerializable {
  // ...
}

To byla moje chvíle, vyčmuchal jsem zde codesmell (zbytečné dědění, které by šlo vyřešit kompozicí). Neomaleně jsem vstoupil do diskuse chválící gadget a sprostě Arthura pohanil. Omlouvám se za to. Mým úmyslem bylo ho postrčit o kus dál, možná rozšířit obzory. Prostě sprostá rada, která by mi v začátcích se C# pomohla nebloudit labyrintem macatých tříd se spoustou dovedností a košatou hierarchií předků a potomků.

Alternativní řešení

V diskusi, kterou jsem tímto vyvolal, padlo i to, že jde o porušení Single Responsibility Principle, které už rozebral Borek. Arthur tedy nabídl, alternativní řešení, jak se s problémem vypořádat:

Samozřejmě jsem si mohl napsat i kašpárkovskou třídu, co má dvě statické metody (Serializuj a Deserializuj) a veřejný parametr „Dictionary“… šlo by to vyřešit mnoha způsoby, lišícími se co do pracnosti, elegance a efektivity, a já se rozhodl nedělat „composition blackbox“, ale podědit třídu – především proto, že bych musel zpřístupňovat spoustu veřejných metod od původní generiky, nebo deklarovat vložený objekt jako veřejný.

public static class DictionarySerializer<TKey, TValue> {
  public static byte[] Serialize(Dictionary<TKey, TValue> dictionary) {
    // ...
  }
  public static Dictionary<TKey, TValue> Deserialize(byte[] data) {
    // ...
  }
}

Přejdu teď composition blackbox – vrátím se snad k němu někdy jindy, ale zastavím se u statických metod. Myslím si totiž, že to je další cesta do pekel… :)

Staticky vs. Instančně

Na toto téma se vedlo jedno z vláken té jinak pěkné diskuse o šikovném gadgetu. (Platíte koncesionářské poplatky?) Osobně zastávám názor, že je lepší se statickým helperům vyhýbat. Jednak ze zkušenosti a druhak z některých signálů a pouček správného OO návrhu.

V objektových jazycích odvozených od C jsme si zvykli používat třídy. Třída je předpis, podle kterého se vyrábějí objekty. Objekty jsou přenašeči dat nebo službami. Mohou být tedy obdařeny rozhraním, přes které s ním komunikují jiné objekty. Jenže ve světě Céčkových jazyků, můžeme mít tzv. statické členy. Statický člen existuje jen jednou, po celou dobu života aplikace.

Jenže, co je to život aplikace? Nevím jak je to přesně v PHP, ale myslím, že tam je to cca jeden požadavek. Statické proměnné tu slouží jako šikovná náhrada globálních proměnných a statické metody dovolují volat akce bez nudného vytváření instance třídy. To je jistě super. Ve světě dotnetu je to však mnohem složitější. V ASP.NET žije aplikace dokud ji někdo nevypne, tj. neresetuje aplikační pool, nezmění konfiguraci nebo neaktualizuje binárky. Takže u statického členu nikdy netušíte, jak dlouho bude žít.

Dalším problémem je konkurence. V PHP se aplikace spouští při každém požadavku a po jeho skončení opět vyhnije a to vše se děje v rámci jednoho vlákna. V ASP.NET žije aplikace mnoho požadavků, které jsou zpracovány samostatnými vlákny. Vzhledem k tomu, že statické členy jsou v aplikaci jen jednou a to pro více vláken, musíte najednou začít řešit konkurenční přístup, k těmto členům.

Další z problémů statických členů je ten, že třída není objekt, tudíž by se s členy třídy nemělo počítat v objektovém návrhu. :) Statické metody ani vlastnosti nelze popsat rozhraním, při jejich užití vzniká úzká vazba. Takovéto členy se také krásně vyhýbají dědičnosti. Nelze je přepsat tradičními postupy.

Takhle bych ve zkratce shrnul hlavní nevýhody statického přístupu. Platí jen pro určité případy. Nemusíte se s nimi nutně setkat a pro váš konkrétní případ mohou být i výhodné. Pokud však navrhujete API, které má být znovupoužitelné (hlavní výhoda OOP), nikdy nevíte, v jakém prostředí poběží. A když už píšeme objektově, tak proč rovnou nepsat tak, aby naše třídy znovupoužitel­né byly?

Jak tedy s těmi helpery?

Jak říká Michal Bláha, „statický helpery jsou výbornej syntax sugar.“ Jasně, proč ne? Ve skriptech může být statický helper jasným přínosem. Je ale třeba myslet na některá pravidla.

Základním pravidlem, pokud chci vytvořit statický helper, je vytvořit instanční implementaci. Dobrou ukázkou tohoto přístupu je například System.IO.File, který je statickou fasádou nad System.IO.FileInfo. Podobně funguje např. i metoda Rarous.TexyNet.Texy.Process, která slouží k rychlému převodu textu do HTML, ale je tu i silné instanční API, které tato metoda volá.

Závěr

Statické helpery jsou zlo, když jsou primárním návrhem a taky jediným. Pokud dosahujete kompozice objektů pomocí dependency injection, jsou pro vás statické helpery nedosažitelné (bez napsání instančního wraperu). Když píšete unit testy, nemůžete snadno statický helper nahradit. Pokud máte statické vlastnosti, musíte myslet na konkurenční přístup a životnost zdrojů, které takto zapouzdřujete.

public interface IDictionarySerializer<TKey, TValue, TData> {
  TData Serialize(IDictionary<TKey, TValue> dictionary);
  IDictionary<TKey, TValue> Deserialize(TData data);
}

Přece jen existuje více cest k cíli a je možné, že se někde šeredně pletu. Jaký je váš pohled na věc?

Autor: Aleš Roubíček | 5x 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!

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!