Si sa sono un fun di Castle Windsor e in generale del mondo IoC, una cosa però veramente tediosa, prona ad errori, scomoda e decisamente ingombrante dei framework di Inversion of Control è la gestione del file di configurazione, soprattutto se usate massicciamente i generics. Questo perchè per gestire una situazione, decisamente triviale, come la seguente:
public interface IMyComponent<T>
where T : IDispatcher
{
}
public interface IDispatcher
{
void Say( String msg );
}
class MyComponent : IMyComponent<IDispatcher>
{
public MyComponent( IDispatcher dispatcher )
{
dispatcher.Say( "from MyComponent.ctor" );
}
}
class MyDispatcher : IDispatcher
{
}
il file di configurazione che ne consegue è qualcosa del tipo:
<components>
<component
id="dispatcher"
service="Sample.IDispatcher, Sample"
type="Sample.IDispatcher, Sample" />
<component
id="myComponent"
service="Sample.IMyComponent`1[[Sample.IDispatcher, Sample]], Sample"
type="Sample.MyComponent, Sample" />
</components>
notate come la gestione dei generics in forma di “full type name” non sia proprio “user friendly”, per ovviare a questo problema tempo fa mi ero inventato un tool da command line che fosse in grado di analizzare gli assembly del progetto e sulla base di una serie di atrtributi custom costruire lo scheletro del file di configurazione. la cosa funzionava e funziona tutt’ora molto bene, ma al complicarsi della configurazione il supporto che vi da il tool è sempre minore.
A questo punto mi sono fatto una domanda: ma quale è il vantaggio di avere la configurazione in un file xml esterno?
la prima risposta potrebbe essere quella di avere la possibilità di manipolare la configurazione a caldo… ma è proprio vero che serva? imho neanche lontanamente se non in casi veramente triviali… cioè se stiamo usando un framewrok di IoC in una applicazione corposa prima di mettere mano alla configurazione in produzione ci pensiamo ben più di 2 volte e passiamo da una serie di stage per testare la nuova configurazione ergo a che ci serve la complessità di un file xml? se la pensiamo unita alle possibilità infide di errore assolutamente a nulla.
Perchè allora non pensare di esprimere in una forma diversa la configurazione? perchè non farlo direttamente in C#?
n.d.r.:Attualmente ci sono anche altre possibilità tra cui la più blasonata, ma con tutta una serie di limiti, è sicuramente Binsor un linguaggio per DSL che si integra con il framework.
Si potrebbe cioè pensare di esprimere la configurazione in una sintassi a noi ben nota, typesafe e compile time checked, esprimerla in un assembly separato e caricare quallo a runtime e usarlo per configurare il container. In questo modo per variare la configurazione ci basterebbe ricompilare quel singolo assembly e rifare il deploy solo di quello.
Con al versione attuale di Castle (1.0RC1) è tutto tranne che un’operazione semplice perchè l’API esposta dal Kernel è tutto tranne che semplice ed intuitiva.
Ma… se recupariamo l’ultimissa versione di Castle, la trunk via subversion, ci troviamo di fronte alla possibilità di esprimere la configurazione sopra citata in una maniera decisamente più naturale:
IWindsorContainer container = new WindsorContainer();
IKernel k = container.Kernel;
k.Register( Component
.For<IMyComponent<IDispatcher>>()
.Named( "iMyComponent" )
.ImplementedBy<MyComponent>()
.LifeStyle.Is( Castle.Core.LifestyleType.Singleton )
.Parameters( Parameter
.ForKey( "dispatcher" )
.Eq( "${iDispatcher}" ) )
);
k.Register( Component
.For<IDispatcher>()
.Named( "iDispatcher" )
.ImplementedBy<MyDispatcher>() );
utilizzando infatti il supporto per le fluent interfaces possiamo reggiungere lo stesso scopo che raggiungiamo con il file xml e continuare ad usare il motore di IoC come siamo abituati:
IMyComponent<IDispatcher> cmp = container.Resolve<IMyComponent<IDispatcher>>();
cmp.Execute();
non male, decisamente non male.
.m