Versioning
Tutti i ragionamenti relativi al versioning si applicano unicamente agli assembly dotati di strong name: un assembly che ne è privo, anche se può avere un attributo di versione, non è soggetto ai controlli di versione effettuati dal runtime, può essere usato unicamente come assembly privato e come tale viene caricato, indipendentemente dalla versione richiesta dal chiamante.
Assembly senza strong name
Per verificare questo comportamento, usiamo un assembly (fooasm.dll) che restituisce una stringa contenente il numero di versione, compiliamo l’eseguibile (footest.exe) che referenzia questa versione dell’assembly, modifichiamo poi l’assembly cambiando la versione, senza ricompilare l’eseguibile.
Questi sono i file di partenza:
using System; using System.Reflection; [assembly:AssemblyVersion("1.0.0.0")] public class FooAsm { public static string GetName() { return "Answer:FooAsm v 1.0.0.0"; } }
using System; public class FooTest { public static void Main() { Console.WriteLine( "Asm = {0}", FooAsm.GetName() ); } }
Per compilarli usiamo:
> csc /target:library fooasm.cs
> csc footest.cs /r:fooasm.dll
A questo punto eseguendo footest.exe otteniamo:
Asm = Answer:FooAsm v 1.0.0.0
Prima di proseguire, osserviamo un estratto dei manifest dei due moduli. L’eseguibile contiene un riferimento a fooasm completo di versione:
.assembly extern fooasm
{
.ver 1:0:0:0
}
Ovviamente il manifest dell’assembly fooasm.dll in questo momento ha una versione corrispondente a quella referenziata da footest.exe:
.assembly fooasm
{
.hash algorithm 0x00008004
.ver 1:0:0:0
}
Modifichiamo fooasm.dll usando quest’altra versione della stessa classe:
using System; using System.Reflection; [assembly:AssemblyVersion("2.2.2.2")] public class FooAsm { public static string GetName() { return "Answer:FooAsm v 2.2.2.2"; } }
Compiliamo soltanto il modulo fooasm.dll utilizzando il sorgente appena visto:
> csc /target:library /out:fooasm.dll fooasm_v2.cs
Riproviamo ad eseguire footest.exe:
Asm = Answer:FooAsm v 2.2.2.2
Ovviamente il manifest di footest.exe non è cambiato, e sicuramente referenzia ancora la versione 1.0.0.0 di fooasm. L’assembly fooasm.dll però è stato ricompilato, e nel suo manifest scopriamo una versione diversa:
.assembly fooasm
{
.hash algorithm 0x00008004
.ver 2:2:2:2
}
La mancata corrispondenza tra versione richiesta da footest.exe e versione dichiarata da fooasm.dll non provoca nessun errore, perché l’assembly è privato e privo di strong name e, come abbiamo visto, in queste condizioni il runtime non effettua nessun controllo di versione.
Assembly con strong name
Chiuso il discorso per gli assembly privi di strong name, da qui in avanti consideriamo che un assembly ne sia dotato.
La versione è sempre presente in uno strong name. Se tale attributo non è specificato nella compilazione dell’assembly, si assume che la versione sia 0.0.0.0.
Allo stesso modo, un riferimento ad uno strong name comprende un numero di versione.
Se non c’è corrispondenza tra versione richiesta e versioni disponibili di un assembly (se è installato nella GAC può essercene più d’una), l’assembly non viene caricato.
Per ridirezionare la versione di un assembly, caricando una versione di assembly diversa rispetto a quella richiesta, è possibile agire a diversi livelli, nell’ordine:
- Application config file
- Publisher policy file
- Machine config file
In tutti e tre i casi si tratta di file di configurazione che condividono lo stesso schema XML.
Il publisher policy file è un file di configurazione creato dall’autore di un assembly, che dichiara uno schema di compatibilità dell’assembly (ad esempio, le versioni comprese tra 1.0.0.0 e 1.2.5.1 sono ridirezionate sulla versione 1.3.0.0, mentre le versioni tra 2.0.0.0 e 2.1.3.0 sono ridirezionate sulla versione 2.2.0.0). Questo file deve essere firmato digitalmente con la stessa chiave dell’assembly a cui si riferisce e va installato nella GAC insieme ai componenti che deve ridirezionare.
L’application config file è il file di configurazione dell’applicazione (se l’applicazione si chiama footest.exe, il file di configurazione si chiama footest.exe.config e si trova nella stessa directory). La logica di ridirezione che può definire è analoga a quella del publisher policy file. Se è presente un publisher policy file, l’application config file può inibirne gli effetti con questa direttiva:
<publisherPolicy apply="no">
Il machine config file è il file di configurazione a livello di macchina, che agisce per tutti gli assembly e può essere modificato solo da un utente amministratore. Le disposizioni contenute in questo file si sovrappongono a quelle eventualmente presenti nell’application config file. Non è però frequente definire una direttiva di ridirezione delle versioni di un assembly a livello di macchina, perché tali specifiche dovrebbero essere distribuite a livello di publisher policy file, mentre i file di configurazione a livello di applicazione e di macchina andrebbero usati solo per fix temporanee, in attesa di nuovi rilasci da parte del produttore.
L’ordine con cui vengono considerati questi file è il seguente:
1) Application config file – è il primo ad essere considerato; può disabilitare l’applicazione del publisher policy file, nel qual caso si passa direttamente al machine config file.
2) Publisher policy file – agisce ridirezionando la versione già modificata dall’application config file; se la versione 1.0.0.0 referenziata per l’assembly fooasm è stata ridirezionata alla versione 2.0.0.0 dal file di configurazione dell’applicazione, il publisher policy file agisce su una richiesta per la versione 2.0.0.0, ed eventuali ridirezionamenti della versione 1.0.0.0 non sono presi in considerazione.
3) Machine config file – ha sempre l’ultima parola e non può essere disabilitato; prende in considerazione la versione eventualmente già ridirezionata in base ai due file di configurazione precedenti.
Application config file
Replichiamo l’esempio precedente, questa volta usando uno strong name.
Prima di tutto creiamo una coppia di chiavi.
> SN –k publicprivate.snk
Poi definiamo l’assembly fooasm.dll dotato di strong name con versione 1.0.0.0, referenziandolo da footest.exe.
using System; using System.Reflection; [assembly:AssemblyKeyFile("publicprivate.snk")] [assembly:AssemblyDelaySign( false )] [assembly:AssemblyVersion("1.0.0.0")] public class FooAsm { public static string GetName() { return "Answer:FooAsm v 1.0.0.0"; } }
using System; public class FooTest { public static void Main() { Console.WriteLine( "Asm = {0}", FooAsm.GetName() ); } }
Compiliamo con:
> csc /target:library fooasm.cs
> csc footest.cs /r:fooasm.dll
Eseguendo footest.exe otteniamo:
Asm = Answer:FooAsm v 1.0.0.0
Fin qui tutto bene, con la differenza che in footest.exe stiamo referenziando uno strong name.
.assembly extern fooasm
{
.publickeytoken = (65 DD E9 FD 4C EE 9B 6D ) // e...L..m
.ver 1:0:0:0
}
Modifichiamo fooasm.dll in modo da cambiare la versione. Notare che la coppia di chiavi usata non cambia.
using System; using System.Reflection; [assembly:AssemblyKeyFile("publicprivate.snk")] [assembly:AssemblyDelaySign( false )] [assembly:AssemblyVersion("2.2.2.2")] public class FooAsm { public static string GetName() { return "Answer:FooAsm v 2.2.2.2"; } }
Compiliamo soltanto il modulo fooasm.dll con questo codice:
> csc /target:library /out:fooasm.dll fooasm_v2.cs
Riproviamo ad eseguire footest.exe:
Unhandled Exception: System.IO.FileLoadException: The located assembly's manifes t definition with name 'fooasm' does not match the assembly reference. File name: "fooasm" at FooTest.Main()
Il caricamento fallisce. L’unica cosa che è cambiata è la versione, perché in fooasm.dll è stata usata la stessa chiave della versione precedente, che genera lo stesso public key token.
A questo punto, se ricompilassimo footest.exe cambieremmo il riferimento allo strong name esterno, aggiornandone la versione. Non è quello che faremo, perché ci interessa capire come definire una regola di ridirezione della versione di fooasm.dll, tale che tutte le richieste per la versione 1.0.0.0 vengano soddisfatte con il caricamento della versione 2.2.2.2.
Possiamo ottenere questo risultato con il tag bindingRedirect nel file di configurazione dell’applicazione.
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.2.2.2" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
Lo schema XML che definisce l’uso di bindingRedirect è identico per tutti i file di configurazione che useremo. All’interno del tag assemblyBinding si definisce l’identità dell’assembly a cui si fa riferimento, specificando poi uno o più tag bindingRedirect che forniscono il mapping per il ridirezionamento delle versioni.
Potremmo avere dei file con più tag bindingRedirect per lo stesso assembly:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.2.2.2" /> <bindingRedirect oldVersion="1.1.0.0" newVersion="2.2.2.2" /> </dependentAssembly> </assemblyBinding>
Altro aspetto importante è la possibilità di definire in un tag bindingRedirect un intervallo di versioni per oldVersion:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="1-1.3.5.9" newVersion="2.2.2.2" /> </dependentAssembly> </assemblyBinding>
In questo caso tutte le versioni comprese tra 1.0.0.0 (i numeri omessi sono sostituiti da 0) e 1.3.5.9 vengono ridirezionate sulla versione 2.2.2.2.
Publisher policy file
Chi crea un componente dovrebbe sapere bene quali sono le possibili compatibilità, quindi è la persona migliore per definire uno schema di ridirezione delle versioni del suo componente.
Negli esempi che vedremo, il codice di partenza di fooasm.dll e footest.exe è lo stesso usato nella sezione Application Config.
Il publisher policy file è un file di configurazione specifico per un certo componente, che può essere creato solo dall’autore del componente, in quanto è l’unico a possedere la coppia di chiavi utilizzate per firmare digitalmente l’assembly. Il publisher policy file agisce su tutti i componenti, condivisi e privati, dotati dello stesso nome e public key token. Perché abbia effetto, il publisher policy file deve essere installato nella GAC.
Il publisher policy file contiene esattamente le stesse informazioni di ridirezione della versione di un componente che si possono inserire in un application config file. La differenza rispetto a questo è che non si possono specificare schemi di ridirezione per altri assembly, o altre informazioni di configurazione del componente.
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.2.2.2" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
Il nome di questo file non è molto importante, perché va soltanto usato per creare un publisher policy assembly, che è un vero e proprio assembly che sarà distribuito per installare il publisher policy file nella GAC.
Per ottenere un publisher policy assembly si usa il tool al.exe (Assembly Linker). Vediamo il comando da usare in questo caso:
> al /link:redir_1.config /out:policy.1.0.fooasm.dll /keyfile:publicprivate.snk
Il risultato di quest’operazione è un assembly multi-modulo, in cui policy.1.0.fooasm.dll è il file che contiene il manifest, mentre redir_1.config è un modulo di risorse parte dell’assembly. Il collegamento è definito da questa direttiva, che definisce una risorsa esterna all’assembly:
.mresource public redir_1.config
{
.file redir_1.config at 0x00000000
}
Notare che il nome del publisher policy assembly deve seguire questo formato:
policy.majorNumber.minorNumber.mainAssemblyName.dll
Come si vede, in questo caso si entra nel merito delle parti che compongono un numero di versione, che ha questo formato:
<major version>.<minor version>.<build>.<revision>
Solo i primi due numeri della versione sono presi in considerazione per la definizione di un publisher policy assembly: questi due numeri devono corrispondere alla versione dell’assembly che viene ridirezionate. Ci sono alcune implicazioni:
- può esistere un solo publisher policy assembly per tutti gli assembly che hanno la stessa coppia <major version>.<minor version>;
- ogni volta che cambia il numero di versione <major version> o <minor version> si rende necessario definire un nuovo publisher policy assembly per ridirezionare tali versioni dell’assembly;
- l’oggetto della corrispondenza è il numero di versione richiesto dall’assembly consumer, non il numero di versione a cui eventualmente si ridireziona la richiesta.
Vediamo gli effetti causati dal publisher policy assembly.
Proviamo a compilare in fooasm.dll la versione 1.0.0.0 del componente richiesto da footest.exe.
> csc /target:library fooasm.cs
> csc footest.cs /r:fooasm.dll
Eseguendo footest.exe otteniamo:
Asm = Answer:FooAsm v 1.0.0.0
A questo punto installiamo il publisher policy assembly (che abbiamo compilato in precedenza):
> gacutil /i policy.1.0.fooasm.dll
Notare che fooasm.dll è ancora un assembly privato, benché sia dotato di strong name. A questo punto, provando ad eseguire nuovamente footest.exe, otteniamo questo errore:
Unhandled Exception: System.IO.FileLoadException: The located assembly's manifes t definition with name 'fooasm' does not match the assembly reference. File name: "fooasm" at FooTest.Main()
Nei dettagli di fusion log si può osservare che non è stato trovato l’assembly richiesto, nella versione 2.2.2.2.
Proviamo a compilare fooasm_v2.cs in fooasm.dll, così da soddisfare la richiesta di questa versione:
> csc /target:library /out:fooasm.dll fooasm_v2.cs
Se eseguiamo footest.exe vedremo che viene richiamata correttamente la versione 2.2.2.2 di fooasm.dll.
Asm = Answer:FooAsm v 2.2.2.2
Abbiamo fatto le prove con degli assembly privati, ma se avessimo installato nella GAC entrambe le versioni di fooasm.dll, adesso vedremmo che tutti i tentativi di richiamare la versione 1.0.0.0 sarebbero ridirezionati alla versione 2.2.2.2. La versione 1.0.0.0 diventerebbe praticamente inutile, anche se, come vedremo più avanti in Override di publisher policy file, è sempre possibile che gli effetti del publisher policy file siano disabilitati per un’applicazione specifica.
Il numero di versione (<major version>.<minor version>) che fa parte del nome del publisher policy assembly non va confuso con la versione dell’assembly stesso: in fin dei conti si tratta sempre di un assembly, e come tale ha un suo numero di versione.
Se vengono installate nella GAC diverse versioni dello stesso publisher policy assembly, viene preso in considerazione solo quello più recente (con il numero di versione maggiore). Ricordiamo che stiamo parlando di versione di assembly, non parliamo del numero che fa parte del nome del file.
Per fare un esempio, proviamo a creare un altro publisher policy file:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="3.4.5.6" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
Installiamolo nella GAC specificando la versione 3.0.0.0:
> al /link:redir_2.config /out:policy.1.0.fooasm.dll /keyfile:publicprivate.snk /v:3.0.0.0
> gacutil /i policy.1.0.fooasm.dll
A questo punto nella GAC esistono due versioni dello stesso publisher policy assembly:

La versione 0.0.0.0 di policy.1.0.fooasm è quella installata durante la prima prova, quando non abbiamo specificato il parametro /v per il comando al. La versione 3.0.0.0 dello stesso assembly è l’unica che viene presa in considerazione, soppiantando quelle con una numerazione più vecchia. Notare che conta solo questa versione e non l’ordine di installazione, quindi installando una eventuale versione 2.0.0.0 di policy.1.0.fooasm, continuerebbe ad essere utilizzata la versione 3.0.0.0, perché ha il numero di versione maggiore.
Eseguendo footest.exe a questo punto otteniamo un errore:
Unhandled Exception: System.IO.FileLoadException: The located assembly's manifes t definition with name 'fooasm' does not match the assembly reference. File name: "fooasm" at FooTest.Main()
L’assembly fooasm ricercato è ora la versione 3.4.5.6. Compiliamo quindi un assembly fooasm con tale versione.
using System; using System.Reflection; [assembly:AssemblyKeyFile("publicprivate.snk")] [assembly:AssemblyDelaySign( false )] [assembly:AssemblyVersion("3.4.5.6")] public class FooAsm { public static string GetName() { return "Answer:FooAsm v 3.4.5.6"; } }
La compilazione ricopre l’assembly precedente: per ora continuiamo a lavorare con assembly privati.
> csc /target:library /out:fooasm.dll fooasm_v3.cs
Ora footest.exe richiama correttamente il nuovo assembly:
Asm = Answer:FooAsm v 3.4.5.6
Installando nella GAC le diverse versioni di fooasm.dll il comportamento non cambia: viene caricata la versione specificata in base alle direttive di ridirezione definite nel publisher policy file.
Compiliamo e installiamo le 3 versioni di fooasm.dll.
> csc /target:library /out:fooasm.dll fooasm.cs
> gacutil /i fooasm.dll
> csc /target:library /out:fooasm.dll fooasm_v2.cs
> gacutil /i fooasm.dll
> csc /target:library /out:fooasm.dll fooasm_v3.cs
> gacutil /i fooasm.dll
Analizzando la GAC, verifichiamo la presenza delle tre versioni dello stesso assembly.

Provando ad eseguire footest.exe (che, ricordiamo, referenzia la versione 1.0.0.0), continua ad essere caricata la versione 3.4.5.6 di fooasm, perché il publisher policy assembly attivo ridireziona ancora la versione 1.0.0.0 di fooasm sulla versione 3.4.5.6.
Override di publisher policy file
Come abbiamo già detto, il file di configurazione dell’applicazione (application config file) può annullare gli effetti del publisher policy file.
Prima di approfondire l’argomento, valutiamo cosa succede se esistono sia un publisher policy file che un application config file. Immaginiamo di avere una richiesta per la versione 1.0.0.0 di fooasm da parte di footest.exe. Nello scenario che ipotizziamo abbiamo questo file di configurazione dell’applicazione:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.3.4.5" /> <dependentAssembly> </assemblyBinding> </runtime> </configuration>
Abbiamo anche questo publisher policy file:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="2.3.4.5" newVersion="4.5.6.7" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
Questa è la sequenza di ridirezioni che si verifica:
- footest.exe richiede fooasm 1.0.0.0
- footest.exe.config ridireziona la richiesta su fooasm 2.3.4.5
- policy.2.3.fooasm ridireziona la richiesta su fooasm 4.5.6.7
Il file di configurazione dell’applicazione (footest.exe.config) potrebbe decidere di ignorare la direttiva del publisher policy file (policy.2.3.fooasm), fermando la ridirezione alla versione 2.3.4.5. Per farlo si usa il tag <publisherPolicy>. Il file di configurazione dell’applicazione potrebbe anche specificare questo tag senza necessariamente ridirezionare la versione di un assembly: in questo caso la versione richiesta dall’applicazione resterebbe immutata (tranne eventuali ridirezioni del machine config file, che non sono annullabili).
Il tag <publisherPolicy> può essere definito all’interno del tag <dependentAssembly> per avere effetto su un singolo assembly referenziato, o all’interno di <assemblyBinding> per avere effetto su tutti gli assembly referenziati.
Prepariamo il terreno per dimostrarne il funzionamento.
Compiliamo footest.exe in modo che usi la versione 1.0.0.0 di fooasm.dll (gli esempi sono sempre gli stessi, rivediamo i sorgenti solo per completezza).
using System; using System.Reflection; [assembly:AssemblyKeyFile("publicprivate.snk")] [assembly:AssemblyDelaySign( false )] [assembly:AssemblyVersion("1.0.0.0")] public class FooAsm { public static string GetName() { return "Answer:FooAsm v 1.0.0.0"; } }
using System; public class FooTest { public static void Main() { Console.WriteLine( "Asm = {0}", FooAsm.GetName() ); } }
Questa la compilazione:
> csc /target:library fooasm.cs
> csc footest.cs /r:fooasm.dll
A questo punto modifichiamo fooasm.dll, trasformandolo nella versione 2.3.4.5:
using System; using System.Reflection; [assembly:AssemblyKeyFile("publicprivate.snk")] [assembly:AssemblyDelaySign( false )] [assembly:AssemblyVersion("2.3.4.5")] public class FooAsm { public static string GetName() { return "Answer:FooAsm v 2.3.4.5"; } }
Modifichiamo anche la configurazione dell’applicazione, che ridireziona la versione 1.0.0.0 di fooasm sulla versione 2.3.4.5.
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.3.4.5" /> <dependentAssembly> </assemblyBinding> </runtime> </configuration>
Funzionerebbe tutto bene (footest.exe richiede la versione 1.0.0.0 di fooasm, la richiesta è ridirezionata sulla versione 2.3.4.5 che è quella effettivamente disponibile), se non fosse che nel frattempo qualcuno ha installato nella GAC un publisher policy file per la versione 2.3 di fooasm che ridireziona la versione 2.3.4.5 sulla versione 4.5.6.7 (il file di configurazione è già stato mostrato all’inizio, policy.2.3.fooasm).
Se non esiste una versione 4.5.6.7 di fooasm, eseguendo footest.exe otterremo il solito errore di assembly non trovato:
Unhandled Exception: System.IO.FileLoadException: The located assembly's manifes t definition with name 'fooasm' does not match the assembly reference. File name: "fooasm" at FooTest.Main()
Questo esempio è molto interessante, perché nonostante il file di configurazione dell’applicazione ridirezioni la richiesta originale di footest.exe sulla versione 2.3.4.5 di fooasm, che è esattamente nella stessa directory di footest.exe, l’effetto del publisher policy file è quello di caricare una versione diversa. La stranezza può derivare dal fatto che ci si potrebbe aspettare che un assembly privato prenda sempre il sopravvento, mentre non è assolutamente così. È auspicabile che questa sia la cosa giusta da fare (chi scrive il publisher policy file ha sicuramente delle ottime ragioni), ma qualora il risultato non sia quello desiderato, possiamo disabilitare l’applicazione del publisher policy file.
Modifichiamo il file di configurazione dell’applicazione in questo modo:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <publisherPolicy apply="no" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.3.4.5" /> <dependentAssembly> </assemblyBinding> </runtime> </configuration>
Il tag <publisherPolicy> che è stato aggiunto disabilita l’applicazione dell’eventuale publisher policy file per tutti i riferimenti all’assembly fooasm da parte di quest’applicazione.
In questo esempio si usa la sintassi per disabilitare il publisher policy file su un solo assembly: questa dovrebbe essere la situazione più comune, perché in teoria tale intervento ha senso solo qualora un publisher policy file crei delle incompatibilità su un’applicazione esistente, intervenendo così solo sull’assembly che dà dei problemi.
Eseguendo footest.exe vediamo che richiama l’assembly che ci aspettiamo:
Asm = Answer:FooAsm v 2.3.4.5
Come abbiamo detto, è possibile disabilitare il publisher policy file per un singolo assembly; ciò può avvenire senza necessariamente definire anche una ridirezione di versione:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <publisherPolicy apply="no" /> <dependentAssembly> </assemblyBinding> </runtime> </configuration>
In questo caso l’applicazione footest.exe richiama l’assembly fooasm nella versione specificata al momento della compilazione di footest.exe, ignorando eventuali publisher policy file installati nella GAC.
Nell’esempio che segue, invece, si disabilitano i publisher policy file per tutti gli assembly richiamati da footest.exe:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <publisherPolicy apply="no" /> </assemblyBinding> </runtime> </configuration>
Ricordiamo che eventuali ridirezioni definite nel machine config file non sono annullabili, quindi anche con il file di configurazione dell’applicazione appena visto non si garantisce il caricamento delle versioni effettivamente richieste da footest.exe.
Machine config file
Il file di configurazione a livello di macchina mantiene la sintassi del file di configurazione dell’applicazione; i suoi effetti, però, agiscono in cascata rispetto alle altre due configurazioni possibili (application config e publisher policy file). In pratica l’amministratore di una macchina ha sempre l’ultima parola rispetto alla ridirezione di versione di un assembly.
Per esempio, è possibile definire in modo inderogabile la ridirezione di un assembly:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="0-2.2.2.2" newVersion="2.2.2.2" /> </dependentAssembly> </assemblyBinding>
In questo caso tutte le versioni anteriori alla 2.2.2.2 richiamano comunque la versione 2.2.2.2. È improbabile però vedere una direttiva simile in una configurazione a livello di macchina, questo tipo di direttiva di upgrade automatico della versione sarà probabilmente più frequente in un publisher policy file. Più probabile vedere un downgrade della versione, magari di una singola versione che sta dando qualche problema:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="fooasm" publicKeyToken="65dde9fd4cee9b6d" /> <bindingRedirect oldVersion="2.2.2.4" newVersion="2.2.2.3" /> </dependentAssembly> </assemblyBinding>
Uno scenario possibile è quello in cui è stata installata la versione 2.2.2.4 di fooasm nella GAC insieme a un publisher policy file che definisce la ridirezione a tale versione. Dopo alcune prove si verifica qualche problema e si appura che la versione precedente è più stabile. Questa configurazione consente di “tornare” alla versione precedente senza disinstallare l’assembly dalla GAC. L’effetto pratico è leggermente diverso dal disinstallare la versione 2.2.2.4, perché l’impostazione in machine.config ridireziona anche eventuali richieste originali di tale versione (ad esempio quando l’assembly referenziato originariamente da footest.exe è la versione 2.2.2.4).
Per questi motivi la configurazione in machine.config è molto delicata e andrebbe usata solamente in casi estremi, preferibilmente in situazioni temporanee (fino alla prossima versione di fooasm).
L'articolo continua con Linee guida