Condividi tramite


Come il runtime individua gli assembly

Annotazioni

Questo articolo è specifico di .NET Framework. Non si applica alle implementazioni più recenti di .NET, incluse .NET 6 e versioni successive.

Per distribuire correttamente l'applicazione .NET Framework, è necessario comprendere in che modo Common Language Runtime individua e associa gli assembly che costituiscono l'applicazione. Per impostazione predefinita, il runtime tenta di eseguire l'associazione con la versione esatta di un assembly con cui è stata compilata l'applicazione. Questo comportamento predefinito può essere sostituito dalle impostazioni del file di configurazione.

Common Language Runtime esegue diversi passaggi durante il tentativo di individuare un assembly e risolvere un riferimento all'assembly. Ogni passaggio è illustrato nelle sezioni seguenti. Il termine probing viene spesso usato quando si descrive come il runtime individua gli assembly; fa riferimento all'insieme di euristiche usato per individuare l'assembly in base al nome e alla cultura.

Annotazioni

È possibile visualizzare le informazioni di associazione nel file di log usando il Visualizzatore log di associazione assembly (Fuslogvw.exe), incluso in Windows SDK.

Avvio del collegamento

Il processo di individuazione e associazione a un assembly inizia quando il runtime tenta di risolvere un riferimento a un altro assembly. Questo riferimento può essere statico o dinamico. Il compilatore registra riferimenti statici nei metadati del manifesto dell'assembly in fase di compilazione. I riferimenti dinamici vengono costruiti in tempo reale in seguito alla chiamata di vari metodi, ad esempio Assembly.Load.

Il modo preferito per fare riferimento a un assembly consiste nell'usare un riferimento completo, inclusi il nome dell'assembly, la versione, la cultura e il token di chiave pubblica (se esiste). Il runtime utilizza queste informazioni per individuare l'assembly, seguendo le istruzioni descritte più avanti in questa sezione. Il runtime usa lo stesso processo di risoluzione indipendentemente dal fatto che il riferimento sia per un assembly statico o dinamico.

È anche possibile creare un riferimento dinamico a un assembly fornendo al metodo chiamante solo informazioni parziali sull'assembly, ad esempio specificando solo il nome dell'assembly. In questo caso, viene eseguita solo la ricerca all'interno della directory dell'applicazione per l'assembly, e non viene effettuato alcun altro controllo. Si crea un riferimento parziale usando uno dei vari metodi per il caricamento di assembly, Assembly.Load ad esempio o AppDomain.Load.

Infine, è possibile creare un riferimento dinamico usando un metodo come Assembly.Load e fornire solo informazioni parziali. Si qualifica quindi il riferimento usando l'elemento <qualifyAssembly> nel file di configurazione dell'applicazione. Questo elemento consente di fornire le informazioni di riferimento complete (nome, versione, impostazioni cultura e, se applicabile, il token di chiave pubblica) nel file di configurazione dell'applicazione anziché nel codice. Usare questa tecnica se si vuole qualificare completamente un riferimento a un assembly all'esterno della directory dell'applicazione o se si vuole fare riferimento a un assembly nella Global Assembly Cache, ma si vuole specificare il riferimento completo nel file di configurazione anziché nel codice.

Annotazioni

Questo tipo di riferimento parziale non deve essere usato con assembly condivisi tra più applicazioni. Poiché le impostazioni di configurazione vengono applicate per applicazione e non per assembly, un assembly condiviso che usa questo tipo di riferimento parziale richiederebbe che ogni applicazione usi l'assembly condiviso per avere le informazioni idonee nel file di configurazione.

Il runtime usa i passaggi seguenti per risolvere un riferimento all'assembly:

  1. Determina la versione corretta dell'assembly esaminando i file di configurazione applicabili, inclusi il file di configurazione dell'applicazione, il file dei criteri dell'editore e il file di configurazione del computer. Se il file di configurazione si trova in un computer remoto, il runtime deve prima individuare e scaricare il file di configurazione dell'applicazione.

  2. Controlla se il nome dell'assembly è stato precedentemente vincolato e, in tal caso, usa l'assembly caricato in precedenza. Se una precedente richiesta per caricare l'assembly non è riuscita, la richiesta fallisce immediatamente senza tentare di caricare l'assembly.

    Annotazioni

    La memorizzazione nella cache degli errori di associazione di assembly è una novità di .NET Framework versione 2.0.

  3. Controlla la Global Assembly Cache. Se l'assembly viene trovato, il runtime usa questo assembly.

  4. Utilizza sonde per l'assemblaggio seguendo questa procedura:

    1. Se le politiche di configurazione e dell'editore non influiscono sul riferimento originale e se la richiesta di associazione è stata creata usando il metodo Assembly.LoadFrom, il runtime verifica la presenza di indicazioni sulla posizione.

    2. Se nei file di configurazione viene trovata una codebase, il runtime controlla solo questo percorso. Se la verifica ha esito negativo, il runtime determina che la richiesta di associazione non è riuscita e non avviene alcun'altra verifica.

    3. Sonde per l'assemblaggio usando l'euristica descritta nella sezione di probing. Se l'assembly non viene trovato dopo l'interrogazione, il runtime richiede a Windows Installer di fornirlo. Questa operazione funge da funzionalità di installazione su richiesta.

      Annotazioni

      Non esiste alcun controllo della versione per gli assembly senza nomi sicuri, né il runtime controlla nella Global Assembly Cache gli assembly senza nomi sicuri.

Passaggio 1: Esame dei file di configurazione

Il comportamento dell'associazione di assembly può essere configurato a livelli diversi in base a tre file XML:

  • File di configurazione dell'applicazione.

  • File dei criteri dell'editore.

  • File di configurazione del computer.

Questi file seguono la stessa sintassi e forniscono informazioni quali i reindirizzamenti di binding, il percorso del codice e le modalità di associazione per assembly specifici. Ogni file di configurazione può contenere un <elemento assemblyBinding> che reindirizza il processo di associazione. Gli elementi figlio dell'elemento< assemblyBinding> includono l'elemento< dependentAssembly>. Gli figli dell'elemento <dependentAssembly> includono l'elemento <assemblyIdentity>, l'elemento <bindingRedirect>, e l'elemento <codeBase>.

Annotazioni

Le informazioni di configurazione sono disponibili nei tre file di configurazione; non tutti gli elementi sono validi in tutti i file di configurazione. Ad esempio, la modalità di associazione e le informazioni sul percorso privato possono trovarsi solo nel file di configurazione dell'applicazione. Per un elenco completo delle informazioni contenute in ogni file, vedere Configurazione delle app tramite file di configurazione.

File di configurazione dell'applicazione

In primo luogo, il Common Language Runtime controlla il file di configurazione dell'applicazione per informazioni che sostituiscono le informazioni di versione salvate nel manifesto dell'assembly richiamante. Il file di configurazione dell'applicazione può essere distribuito con un'applicazione, ma non è necessario per l'esecuzione dell'applicazione. In genere il recupero di questo file è quasi istantaneo, ma in situazioni in cui la base dell'applicazione si trova in un computer remoto, ad esempio in uno scenario basato sul Web, è necessario scaricare il file di configurazione.

Per i file eseguibili client, il file di configurazione dell'applicazione si trova nella stessa directory del file eseguibile dell'applicazione e ha lo stesso nome di base dell'eseguibile con un'estensione .config. Ad esempio, il file di configurazione per C:\Program Files\Myapp\Myapp.exe è C:\Program Files\Myapp\Myapp.exe.config. In uno scenario basato su browser, il file HTML deve usare l'elemento <di collegamento> per puntare in modo esplicito al file di configurazione.

Il codice seguente fornisce un semplice esempio di file di configurazione dell'applicazione. In questo esempio viene aggiunto un oggetto TextWriterTraceListener alla Listeners raccolta per abilitare la registrazione delle informazioni di debug in un file.

<configuration>
   <system.diagnostics>
      <trace useGlobalLock="false" autoflush="true" indentsize="0">
         <listeners>
            <add name="myListener" type="System.Diagnostics.TextWriterTraceListener, system version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" initializeData="c:\myListener.log" />
         </listeners>
      </trace>
   </system.diagnostics>
</configuration>

File dei criteri dell'editore

In secondo luogo, il runtime esamina il file dei criteri dell'editore, se presente. I file dei criteri del publisher vengono distribuiti da un editore di componenti come correzione o aggiornamento per un componente condiviso. Questi file contengono informazioni di compatibilità rilasciate dal server di pubblicazione del componente condiviso che indirizza un riferimento all'assembly a una nuova versione. A differenza dei file di configurazione dell'applicazione e del computer, i file dei criteri dell'editore sono contenuti nel proprio assembly che deve essere installato nella Global Assembly Cache.

Di seguito è riportato un esempio di file di configurazione dei criteri di pubblicazione:

<configuration>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

            <dependentAssembly>
                <assemblyIdentity name="asm6" publicKeyToken="c0305c36380ba429" />
                <bindingRedirect oldVersion="3.0.0.0" newVersion="2.0.0.0"/>
            </dependentAssembly>

        </assemblyBinding>
    </runtime>
</configuration>

Per creare un assembly, è possibile usare lo strumento Al.exe (Assembly Linker) con un comando come il seguente:

Al.exe /link:asm6.exe.config /out:policy.3.0.asm6.dll /keyfile: compatkey.dat /v:3.0.0.0

compatkey.dat è un file di chiave con nome sicuro. Questo comando crea un assembly con nome sicuro che è possibile inserire nella Global Assembly Cache.

Annotazioni

I criteri del server di pubblicazione influiscono su tutte le applicazioni che usano un componente condiviso.

Il file di configurazione dei criteri di pubblicazione esegue l'override delle informazioni sulla versione provenienti dall'applicazione, ovvero dal manifesto dell'assembly o dal file di configurazione dell'applicazione. Se nel file di configurazione dell'applicazione non è presente alcuna istruzione per reindirizzare la versione specificata nel manifesto dell'assembly, il file dei criteri dell'editore esegue l'override della versione specificata nel manifesto dell'assembly. Tuttavia, se nel file di configurazione dell'applicazione è presente un'istruzione di reindirizzamento, i criteri di pubblicazione sostituiscono tale versione anziché quella specificata nel manifesto.

Un file di criteri dell'editore viene usato quando viene aggiornato un componente condiviso e la nuova versione del componente condiviso deve essere prelevata da tutte le applicazioni che usano tale componente. Le impostazioni nel file dei criteri dell'editore sostituiscono le impostazioni nel file di configurazione dell'applicazione, a meno che il file di configurazione dell'applicazione non applichi la modalità provvisoria.

Modalità provvisoria

I file dei criteri dell'editore vengono generalmente installati esplicitamente come parte di un Service Pack o di un aggiornamento di un programma. In caso di problemi con il componente condiviso aggiornato, è possibile ignorare le sostituzioni nel file dei criteri dell'editore usando la modalità provvisoria. La modalità provvisoria è determinata dall'elemento <publisherPolicy apply="yes|no"/> che si trova solo nel file di configurazione dell'applicazione. Specifica se le informazioni di configurazione della politica del publisher devono essere rimosse dal processo di associazione.

La modalità provvisoria può essere impostata per l'intera applicazione o per gli assembly selezionati. Vale a dire, è possibile disattivare la politica per tutti gli assembly che costituiscono l'applicazione, o attivarla per alcuni assembly, ma non per altri. Per applicare in modo selettivo le politiche di pubblicazione agli assembly che costituiscono un'applicazione, impostare <publisherPolicy apply=no/> e specificare quali assembly devono essere interessati usando l'elemento <dependentAssembly>. Per applicare criteri di pubblicazione a tutti gli assembly che costituiscono l'applicazione, impostare <publisherPolicy apply=no/> senza elementi assembly dipendenti. Per altre informazioni sulla configurazione, vedere Configurazione delle app tramite file di configurazione.

File di configurazione del computer

In terzo luogo, il runtime esamina il file di configurazione del computer. Questo file, denominato Machine.config, si trova nel computer locale nella sottodirectory Config della directory radice in cui è installato il runtime. Questo file può essere usato dagli amministratori per specificare le restrizioni di associazione di assembly locali per tale computer. Le impostazioni nel file di configurazione del computer hanno la precedenza su tutte le altre impostazioni di configurazione; Tuttavia, questo non significa che tutte le impostazioni di configurazione devono essere inserite in questo file. La versione determinata dal file dei criteri di amministratore è finale e non può essere sottoposta a override. Le sostituzioni specificate nel file Machine.config influiscono su tutte le applicazioni. Per altre informazioni sui file di configurazione, vedere Configurazione delle app tramite file di configurazione.

Passaggio 2: Controllo degli assembly a cui si fa riferimento in precedenza

Se l'assembly richiesto è stato richiesto anche nelle chiamate precedenti, Common Language Runtime usa l'assembly già caricato. Questo può avere ramificazioni quando si assegnano nomi ad assembly che costituiscono un'applicazione. Per altre informazioni sulla denominazione degli assembly, vedere Nomi di assembly.

Se una richiesta precedente per l'assembly è fallita, le richieste successive per l'assembly vengono immediatamente bloccate senza tentare di caricare l'assembly. A partire da .NET Framework versione 2.0, gli errori di associazione di assembly vengono memorizzati nella cache e le informazioni memorizzate nella cache vengono usate per determinare se tentare di caricare l'assembly.

Annotazioni

Per ripristinare il comportamento delle versioni 1.0 e 1.1 di .NET Framework, che non memorizzavano nella cache gli errori di associazione, includere l'elemento< disableCachingBindingFailures> nel file di configurazione.

Passaggio 3: Controllo della Global Assembly Cache

Per gli assembly con nome sicuro, il processo di associazione continua cercando nella cache globale dell'assembly. La Global Assembly Cache archivia gli assembly che possono essere usati da diverse applicazioni in un computer. Tutti gli assembly nella Global Assembly Cache devono avere nomi sicuri.

Passaggio 4: Individuazione dell'assembly tramite codebase o esplorazione

Dopo che la versione corretta dell'assembly è stata determinata usando le informazioni nel riferimento dell'assembly chiamante e nei file di configurazione e dopo che è stata archiviata nella Global Assembly Cache (solo per assembly con nome sicuro), Common Language Runtime tenta di trovare l'assembly. Il processo di individuazione di un assembly prevede i passaggi seguenti:

  1. Se nel file di configurazione dell'applicazione viene trovato un <elemento codeBase> , il runtime controlla il percorso specificato. Se viene trovata una corrispondenza, l'assembly viene usato e non viene effettuata alcuna ricerca. Se l'assembly non viene trovato lì, la richiesta di associazione ha esito negativo.

  2. Il runtime effettua quindi una ricerca per l'assembly di riferimento usando le regole specificate più avanti in questa sezione.

Annotazioni

Se si dispone di più versioni di un assembly in una directory e si desidera fare riferimento a una determinata versione di tale assembly, è necessario utilizzare l'elemento <codeBase> anziché l'attributo privatePath dell'elemento <di probe> . Se si usa l'elemento <probing>, il runtime smette di eseguire il probing la prima volta che trova un assembly che corrisponde al nome dell'assembly semplice a cui viene fatto riferimento, indipendentemente dal fatto che sia una corrispondenza corretta o meno. Se è una corrispondenza corretta, viene utilizzato quell'assemblaggio. Se non è una corrispondenza corretta, il sondaggio si arresta e il collegamento fallisce.

Individuazione dell'assembly tramite codebase

Le informazioni sulla codebase possono essere fornite usando un <elemento codeBase> in un file di configurazione. Questa codebase viene sempre controllata prima che il runtime tenti di eseguire il probe per l'assembly a cui si fa riferimento. Se un file di criteri dell'editore contenente il reindirizzamento della versione finale contiene anche un <codeBase>, quell'elemento <codeBase> è quello utilizzato. Ad esempio, se il file di configurazione dell'applicazione specifica un <elemento codeBase> e un file di criteri dell'editore che esegue l'override delle informazioni sull'applicazione specifica anche un <elemento codeBase, viene usato l'elemento codeBase><nel file dei criteri dell'editore>.

Se non viene trovata alcuna corrispondenza nella posizione specificata dall'elemento <codeBase> , la richiesta di associazione ha esito negativo e non vengono eseguiti altri passaggi. Quando il runtime determina che un assembly rispetta i criteri stabiliti dall'assembly chiamante, utilizza quell'assembly. Quando viene caricato il file specificato dall'elemento <codeBase>, il runtime verifica che il nome, la versione, la cultura e la chiave pubblica corrispondano al riferimento dell'assembly chiamante.

Annotazioni

Gli assembly a cui si fa riferimento all'esterno della directory radice dell'applicazione devono avere nomi sicuri e devono essere installati nella Global Assembly Cache o specificati usando l'elemento <codeBase> .

Individuazione dell'assembly tramite sonda

Se nel file di configurazione dell'applicazione non è presente alcun <elemento codeBase>, il runtime ricerca l'assembly utilizzando quattro criteri:

  • Base dell'applicazione, ovvero il percorso radice in cui viene eseguita l'applicazione.

  • Attributo di cultura, ovvero l'attributo di cultura dell'assembly a cui viene fatto riferimento.

  • Nome, cioè il nome dell'assembly a cui si fa riferimento.

  • Attributo privatePath dell'elemento <probing>, ovvero l'elenco definito dall'utente di sottodirectory sotto la posizione radice. Questo percorso può essere specificato nel file di configurazione dell'applicazione e nel codice gestito mediante la proprietà AppDomainSetup.PrivateBinPath per un dominio applicativo. Se specificato nel codice gestito, viene prima eseguito il probe del codice privatePath gestito, seguito dal percorso specificato nel file di configurazione dell'applicazione.

Esplorazione delle directory di base e delle directory cultura dell'applicazione

Il runtime inizia sempre a sondare dalla radice dell'applicazione, che può essere un URL o la directory principale dell'applicazione su un computer. Se l'assembly a cui si fa riferimento non viene trovato nella directory base dell'applicazione e non vengono fornite informazioni sulla cultura, il runtime cerca tutte le sottodirectory aventi lo stesso nome dell'assembly. Le directory analizzate includono:

  • [base applicazione] / [nome assembly].dll

  • [application base] / [nome dell'assembly] / [nome dell'assembly].dll

Se per l'assembly a cui si fa riferimento vengono specificate informazioni sulle impostazioni cultura, vengono sondate solo le directory seguenti:

  • [application base] / [culture] / [nome assemblaggio].dll

  • [application base] / [culture] / [nome assembly] / [nome assembly].dll

Sondaggio con l'attributo privatePath

Oltre alle sottodirectory della cultura e alle sottodirectory denominate in base all'assembly di riferimento, il runtime esplora anche le directory specificate utilizzando l'attributo privatePath dell'elemento <probing>. Le directory specificate usando l'attributo privatePath devono essere sottodirectory della directory radice dell'applicazione. Le directory sondate variano a seconda che le informazioni culturali siano incluse nella richiesta di assembly di riferimento.

Il runtime smette di eseguire il probe la prima volta che trova un assembly che corrisponde al nome dell'assembly semplice a cui viene fatto riferimento, indipendentemente dal fatto che si tratti di una corrispondenza corretta o meno. Se è una corrispondenza corretta, viene utilizzato quell'assemblaggio. Se non è una corrispondenza corretta, il sondaggio si arresta e il collegamento fallisce.

Se la cultura è inclusa, vengono verificate le seguenti directory.

  • [application base] / [binpath] / [culture] / [nome assembly].dll

  • [application base] / [binpath] / [culture] / [nome assembly] / [nome assembly].dll

Se le informazioni sulla cultura non sono incluse, vengono esaminate le directory seguenti:

  • [base dell'applicazione] / [binpath] / [nome assembly].dll

  • [application base] / [binpath] / [nome assembly] / [nome assembly].dll

Esempi di analisi

Fornite le seguenti informazioni:

  • Nome dell'assembly a cui si fa riferimento: myAssembly

  • Directory principale dell'applicazione: http://www.code.microsoft.com

  • <L'elemento di probing nel file di> configurazione specifica: bin

  • Cultura: de

Il runtime esamina gli URL seguenti:

  • http://www.code.microsoft.com/de/myAssembly.dll

  • http://www.code.microsoft.com/de/myAssembly/myAssembly.dll

  • http://www.code.microsoft.com/bin/de/myAssembly.dll

  • http://www.code.microsoft.com/bin/de/myAssembly/myAssembly.dll

Più moduli con lo stesso nome

Nell'esempio seguente viene illustrato come configurare più assembly con lo stesso nome.

<dependentAssembly>
   <assemblyIdentity name="Server" publicKeyToken="c0305c36380ba429" />
   <codeBase version="1.0.0.0" href="v1/Server.dll" />
   <codeBase version="2.0.0.0" href="v2/Server.dll" />
</dependentAssembly>

Altre posizioni sondate

È anche possibile determinare la posizione dell'assembly usando il contesto di collegamento corrente. Ciò si verifica più spesso quando viene usato il Assembly.LoadFrom metodo e negli scenari di interoperabilità COM. Se un assembly usa il LoadFrom metodo per fare riferimento a un altro assembly, il percorso dell'assembly chiamante viene considerato un suggerimento su dove trovare l'assembly a cui si fa riferimento. Se si trova una corrispondenza, l'assembly viene caricato. Se non viene trovata alcuna corrispondenza, il runtime continua con la semantica di ricerca e quindi esegue una query in Windows Installer per fornire l'assembly. Se non viene specificato alcun assembly che corrisponde alla richiesta di binding, viene generata un'eccezione. Questa eccezione è un TypeLoadException nel codice gestito se è stato fatto riferimento a un tipo, oppure un FileNotFoundException se un assembly veniva caricato e non è stato trovato.

Ad esempio, se Assembly1 fa riferimento a Assembly2 e Assembly1 è stato scaricato da http://www.code.microsoft.com/utils, tale posizione viene considerata un suggerimento su dove trovare Assembly2.dll. Il runtime ispeziona l'assembly in http://www.code.microsoft.com/utils/Assembly2.dll e http://www.code.microsoft.com/utils/Assembly2/Assembly2.dll. Se Assembly2 non viene trovato in una di queste posizioni, il runtime esegue una query in Windows Installer.

Vedere anche