Abbiamo già avuto modo di fare una lunga digressione sulla possibilità di far convivere, molto felicemente anche, un motore di Inversion of Control e la creazione di istanze di servizi WCF.
Quella soluzione soffre purtroppo di un inconveniente che, a mio modo di vedere, è tutto tranne che trascurabile.
Piccolo ripassino… Smile
Prima di indagare e disquisire facciamo un breve ripasso su come gira il fumo, altresì noto come ciclo di vita di un servizio WCF e attori coinvolti; partendo dal fondo, mettendoci quindi nei panni del servizio WCF:
  1. IInstanceProvider: l’istanza di un servizio WCF è in ultimo fornita (e gestita) da una classe che implementa l’interfaccia IInstanceProvider; Un IInstanceProvider è paragonabile ad un container, ha due simpatici metodi GetInstance e ReleaseInstance che sono decisamente auto esplicativi;
  2. IServiceBehavior: come fa un IInstanceProvider a infilarsi nella pipeline di WCF? lo fa tramite un behavior, per l’esattezza un IServiceBehavior applicato a uno o più endpoint;
  3. ServiceHost: un IServiceBehavior può a sua volta essere inserito nella pipeline di WCF in 2 modi:
    1. tramite file configurazione, ma dovete pagare lo scotto che non avete accesso al processo di creazione dell’istanza del behavior e rischiate di dover ricorrere al famigerato “service locator pattern”;
    2. tramite un ServiceHost custom che in fase di apertura dell’host altro non fa che aggiungere il behavior allalista di quelli da usarsi;
  4. ServiceHostFactory: ok…ma se sono ad esempio hostato in IIS, e quindi ho un file svc, come posso avere controllo sulla creazione del ServiceHost? semplice… tramite una ServiceHostFactory custom che è il primo vero entry point nel processo di creazione di tutto il mondo;
Ora…
out-of-the-box avete fondamentalmente due modi per agganciare una ServiceHostFactory alla pipeline di WCF:
  • Mettendo mano al markup del file .svc e aggiungendo l’attributo “Factory”, consentendovi di specificare una factory specifica per ogni servizio:
<%@ ServiceHost Language="C#" 
Service="MyWebApplication.MyService" 
Factory="MyWebApplication.MyServiceHostFactory" 
%>
  • Oppure definendo nel file di configurazione della vostra applicazione quale deve essere la factory di default per ogni servizio:
<system.serviceModel>
<
serviceHostingEnvironment
>
<
serviceActivations
>
<
add service="MyWebApplication.MyService"
relativeAddress="MyService.svc"
factory="MyWebApplication.MyServiceHostFactory"
/>
serviceActivations
>
serviceHostingEnvironment
>
system.serviceModel
>
Bello…ma…
…non è tutto oro quello che luccica, nel mondo di Inversion of Control e della Dependency Injection c’è una regola aurea: “deve esistere uno ed un solo container”.
Il modello di WCF prevede che venga, per certi versi giustamente, creata un’istanza della factory per ogni servizio che esponete, ma a questo punto nasce un inghippo…dato che, in entrambi i casi di cui sopra, la factory viene esplicitata in maniera dichiarativa non avete nuovamente controllo sulla sua creazione e se volete avere a disposizione un container per Inversion of Control al fine di gestire il ciclo di vita dei vostri servizi siete di nuovo costretti a ricorrere nuovamente a qualcosa basato su “service locator” o porcate simili che implicano l’uso di static…mannaggia…
.Net 4.0 e WCF 4.0: si… può… fare!
vediamo subito il come poi capiamo il cosa; nel vostro simpatico Global.asax potete fare una cosa del tipo:
ApplicationBootstrapper bootstrapper;


protected void Application_Start( object sender, EventArgs e )
{
var root = AppDomain.CurrentDomain.BaseDirectory;
var directory = Path.Combine( root, "bin" );

this.bootstrapper = new ApplicationBootstrapper( directory );
var container = this.bootstrapper.Boot();

var hostFactory = new Hosting.MyServiceHostFactory( container );

RouteTable.Routes.Add( new ServiceRoute( "my", hostFactory, typeof( MyService ) ) );
}
ApplicationBootstrapper non è altro che un wrapper per la creazione e l’inizializzazione di Castle Windsor via MEF, la cosa veramente interessante sono le ultime due righe:
  1. creiamo manualmente (avremmo anche potuto farla risolvere al container) una factory custom a cui passiamo nel costruttore un’istanza del nostro fido container;
  2. sfruttiamo una figata del motore di routing: le ServiceRoute. Una ServiceRoute non è altro che una route speciale che è in grado di attivare un servizio WCF…come?
    1. usando come prefisso della rotta il valore che decidiamo noi, in questo esempio “my”;
    2. usando una factory fornita dall’esterno, in questo caso la nostra;
    3. specificando quale sia il tipo di servizio che quella rotta esporrà;
A questo punto, dopo aver compilato, non vi resta che puntare il browser a “http://my-service-uri/my” per vedere attivato il vostro servizio “MyService” e… se MyService ha una o più dipendenze questa verranno risolte da Castle.
.m