Confessions of a Dangerous Mind

Brain.FlushBuffer()
posts - 176, comments - 234, trackbacks - 93

WPF Prism Technical Concepts: Containers and Services

Come già affermato in qualche mio precedente post, Prism è un’insieme di librerie per la creazione di applicazioni modulari fortemente disaccoppiate. Nella libreria di Prism viene messa a disposizione l’interfaccia IServiceLocator che può essere implementata per crearsi il proprio Container, oppure per adattare containers già esistenti all’utilizzo con CAL. Ovviamente CAL espone già un container “ready for use”: si tratta dell’interfaccia IUnityContainer presente nel namespace Microsoft.Practices.Unity della libreria Unity Application Block.

L’interfaccia IServiceLocator, da implementare SOLO se il container “di default” non fa al caso nostro, è piuttosto semplice, come si può vedere nel seguente snippet:

   1: public interface IServiceLocator : IServiceProvider
   2: {
   3:     object GetInstance(Type serviceType);
   4:     object GetInstance(Type serviceType, string key);
   5:     IEnumerable<object> GetAllInstances(Type serviceType);
   6:     TService GetInstance<TService>();
   7:     TService GetInstance<TService>(string key);
   8:     IEnumerable<TService> GetAllInstances<TService>();
   9: }

Ma come possono essere utilizzate le funzionalità messe a disposizione dal nostro container? CAL lo utilizza in modo pervasivo; ad esempio, anche nella risoluzione di un modulo (fase di Inizialize) viene impiegata la chiamata GetInstance, come si può vedere nello snippet seguente:

   1: protected virtual IModule CreateModule(string typeName)
   2: {
   3:     Type moduleType = Type.GetType(typeName);
   4:     return (IModule)this.serviceLocator.GetInstance(moduleType);
   5: }

Noi possiamo utilizzare il container? Ovviamente si, ma solitamente non si impiegherà direttamente l’interfaccia IServiceLocator, che verrà invece utilizzata da chi necessita di estendere containers di terze parti oppure deve per forza di cose integrarsi con altri containers. Il containers che di solito viene impiegato, come già detto, è lo UnityContainer ed è raggiungibile a livello di bootstrapper, tramite la proprietà Container. Per configurare correttamente il container a livello di bootstrapper, è comunque consigliabile agire mediante override del metodo ConfigureContainer, intervenendo a livello di bootstrapper. E’ altresì possibile agire a livello di modulo per registrare istanze di oggetti che possono essere condivisi tra moduli. Vediamo in dettaglio i vari punti:

   1: namespace SimpleModule1.Services
   2: {
   3:     public interface IEmployeesService
   4:     {
   5:         IEnumerable<string> GetAllEmployees();
   6:     }
   7:  
   8:     public class EmployeesService : IEmployeesService
   9:     {
  10:         #region IEmployeesService Members
  11:  
  12:         public IEnumerable<string> GetAllEmployees()
  13:         {
  14:             List<string> _emps = new List<string>();
  15:             _emps.Add("Hugo Reyes");
  16:             _emps.Add("Jack Shepard");
  17:             _emps.Add("John Locke");
  18:             return _emps;
  19:         }
  20:  
  21:         #endregion
  22:     }
  23: }

Creazione dell’interfaccia IEmployeesService e del servizio EmployeesService. Il tutto è stato posto all’interno dell’assembly del modulo, ma ovviamente potrebbe essere decentrato in un assembly satellite.

   1: protected override void ConfigureContainer()
   2: {
   3:     base.ConfigureContainer();
   4:     this.Container.RegisterInstance<SimpleModule1.Services.IEmployeesService>
   5:     (    
   6:         new SimpleModule1.Services.EmployeesService(),
   7:         new ContainerControlledLifetimeManager()
   8:     );
   9: }

Registrazione del servizio all’interno del container a livello di Bootstrapper. L’istanza viene creata e memorizzata all’interno del container come Singleton, ovvero qualunque modulo abbia necessità di utilizzare tale servizio utilizzerà sempre lo stesso, senza crearne una nuova istanza ogni volta (questo è anche uno dei diversi metodi di comunicazione tra moduli, ma di questo argomento ne parleremo in un futuro post).

   1: public SimpleModule1(IRegionManager regionManager, IUnityContainer container)
   2: {
   3:     _regionManager = regionManager;
   4:     _container = container;           
   5: }
   6:  
   7: public void Initialize()
   8: {
   9:     _regionManager.RegisterViewWithRegion("MainRegion", typeof(Views.SimpleModule1View));
  10:     //Risoluzione del servizio
  11:     Services.IEmployeesService _employeeService = _container.Resolve<Services.IEmployeesService>();
  12:     //Utilizzo del servizio
  13:     IEnumerable<string> _emps = _employeeService.GetAllEmployees();
  14: }

Nell’ultimo snippet si può vedere come il modulo possa, previa “injection” della dipendenza da IUnityContainer, reperire l’istanza del servizio creato in precedenza nel boostrapper e successivamente impiegare l’unico metodo del servizio stesso, ovvero GetAllEmployees. Ribadisco che la soluzione è stata creata al solo scopo di mostrare come, tramite dependency injection e utilizzo del container, sia possibile registrare e condividere servizi tra moduli.

Per finire, una lista dei servizi “di base” messi a disposizione da CAL per la realizzazione di applicazioni modulari:

  • IModuleManager Definisce l’interfaccia per inizializzare e risolvere le referenze ai moduli dell’applicazione;
  • IModuleCatalog contiene i metadati dei moduli presenti nell’applicazione;
  • IModuleInitializer inizializza i moduli
  • IRegionManager registra e risolve le regions, contenitori visuali per il layout;
  • IEventAggregator insieme di eventi disaccoppiati tra publisher e subscriber.
  • ILoggerFacade un wrapper per implementare le logiche di logging dell’applicazione
  • IServiceLocator permette a CAL di accedere al container. Necessaria per effettuare personalizzazioni o estensioni della CAL;

Come al solito, l’invito è quello di provare Prism, scaricandolo a questo indirizzo.

Print | posted on giovedì 20 agosto 2009 14:11 |

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET