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
Hosting di componenti WebAssembly in un'applicazione Blazor static
Creare form tipizzati con Angular
Eseguire una query su SQL Azure tramite un workflow di GitHub
Reactive form tipizzati con FormBuilder in Angular
Miglioramenti nell'accessibilità con Angular CDK
Mascherare l'output di un valore all'interno dei log di un workflow di GitHub
Load test di ASP.NET Core con k6
Eseguire attività pianificate con Azure Container Jobs
Routing statico e PreRendering in una Blazor Web App
Usare il versioning con i controller di ASP.NET Core Web API
Gestire undefined e partial nelle reactive forms di Angular
Applicare il versioning ai nostri endpoint ASP.NET Core Minimal API
I più letti di oggi
- Cambiare la chiave di partizionamento di Azure Cosmos DB
- ASP.NET 2.0 per tutti
- Definire stili a livello di libreria in Angular
- Utilizzare il trigger SQL con le Azure Function
- Ottimizzare le performance delle collection con le classi FrozenSet e FrozenDictionary
- .NET Conference Italia 2023 - Milano e Online
- Come EF 8 ha ottimizzato le query che usano il metodo Contains
- Ottimizzazione dei block template in Angular 17