Solitamente, quando dobbiamo eseguire codice di inizializzazione per un'applicazione ASP.NET, siamo abituati a sfruttare il metodo Application_Start contenuto all'interno di global.asax, che però risulta poco pratico nel momento in cui ci sia la necessità di gestire dipendenze da altri assembly, ognuno con la propria procedura di startup.
Immaginiamo, ad esempio, il caso in cui stiamo sfruttando Unity come container di Inversion of Control, esponendo i servizi applicativi tramite interfacce la cui implementazione concreta si trova in uno o più assembly che la nostra applicazione referenzia. Tipicamente, per configurare il nostro sistema abbiamo a disposizione due strade:
- Utilizzare un approccio centralizzato e basato su XML, ad esempio sfruttando il file di configurazione web.config, ma perdendo però ogni tipo di supporto da parte del designer di Visual Studio;
- Fare in modo che ogni assembly sia in grado di registrare autonomamente i propri oggetti sul container.
Il vantaggio della prima soluzione è quello di poter intervenire sulla configurazione a caldo, senza cioè essere costretti a ricompilare l'applicazione web. Il secondo approccio, invece, è sicuramente più strutturato, e può essere implementato piuttosto facilmente, ad esempio realizzando all'interno di ogni assembly un metodo statico simile al seguente.
public class Initializer { public static void Initialize() { ServiceLocator.Container .RegisterType<ICustomerRepository, CustomerRepository>(); // ... registrazione di altri servizi } }
Lo svantaggio risiede però nel fatto che siamo comunque costretti a invocare questi metodi all'interno di Application_Start, come nell'esempio seguente, con la necessità di effettuare una ricompilazione dell'applicazione nel caso le dipendenze varino. Inoltre, l'inizializzazione deve essere eseguita prima di ogni altro codice di Application_Start, perché quest'ultimo potrebbe potenzialmente utilizzare il container e quindi richiedere che sia completamente configurato.
protected void Application_Start() { Module1.Initialize(); Module2.Initialize(); // altri moduli da inizializzare // ... // qui codice che sfrutta i moduli inizializzati }
Nel caso di un'applicazione ASP.NET 4.0, tuttavia, esiste una terza soluzione, che presenta i vantaggi di entrambe le alternative che abbiamo presentato, e che si basa sull'utilizzo dell'attributo PreApplicationStartMethod. Tramite esso, possiamo specificare un metodo, all'interno di un assembly, che verrà automaticamente eseguito dal runtime di ASP.NET prima della fase di startup, e quindi prima anche del metodo Application_Start.
[assembly: PreApplicationStartMethod(typeof(Initializer), "Initialize")] public class Initializer { public static void Initialize() { ServiceLocator.Container .RegisterType<ICustomerRepository, CustomerRepository>(); } }
Il metodo in questione deve essere statico e privo di parametri. L'aspetto interessante è che questo attributo viene automaticamente individuato tra tutti gli assembly presenti nella cartella \bin, anche se non referenziati dal progetto ASP.NET. Il risultato, quindi, è che se ogni class library possiede il proprio metodo di inizializzazione, di fatto possiamo riconfigurare le dipendenze semplicemente copiando i relativi assembly all'interno della cartella dell'applicazione.
Non è questo l'unico scopo dell'attributo PreApplicationStartMethod: la sua natura, ad esempio, lo rende un'ottima soluzione per configurare a runtime HttpModule, BuildProvider o aggiungere riferimenti a runtime.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Blazor <3 Javascript
Centralizzare la gestione delle entity multitenant in Entity Framework Core
Leggere parametri in QueryString in Blazor
Creare un controllo Expander in un'app Xamarin Forms
Use Firebase in Progressive Web Apps
Creare un Module Initializer in .NET 5
Modificare il layout della paginazione del controllo CarouselView in Xamarin Forms
Condividere una variabile tra stage in una pipeline YAML di Azure DevOps
Introduzione a GitHub
Ottimizzare la compilazione di applicazioni Angular con il Fast and Loose Incremental Checking di TypeScript
Effettuare il tracing asincrono delle chiamate a un'applicazione ASP.NET Core
Creare API GraphQL con ASP.NET Core e HotChocolate
I più letti di oggi
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!
- Creare un record in C#
- Winget: un nuovo package manager per Windows
- il 18/02 c'è il #container & #devops day! https://aspit.co/ContainerDevOpsDay-21 Le iscrizioni sono sempre aperte e la Call For Paper è attiva fino al 28/01! #aspilive #cfp
- Utilizzare il CSS Grid Model per creare il layout di un sito
- Attesa e validazione manuale nelle pipeline YAML di Azure DevOps
- Montare una file share con Azure Container Instance