17

Newtonsoft.Json versioni incompatibili con lo stesso nome sicuro, solo cambiando la versione del file.incompatibilità della versione di NewtonSoft JSON.NET (inferno della DLL)

Secondo MSDN:

Assiemi che hanno lo stesso nome sicuro deve essere identico.

A causa di questo le nostre pause di applicazione se altra applicazione, al di fuori del nostro controllo, mette versione diversa del Newtonsoft.Json.dll nella GAC ​​

C'è un modo per forzare .NET per caricare una versione specifica che bisogno?

Aggiornamento:

Mi spiego problema più in profondità.

In .NET, per quanto ne so, non esiste alcun meccanismo per risolvere gli assembly prima che CLR tenti di risolverli e fallire.

C'è solo l'evento AppDomain.AssemblyResolve e si attiva solo quando l'assembly non è stato risolto. Di solito è abbastanza.

Ma in caso di Newtonsoft.Json non riesce a risolvere l'assembly, semplicemente carica quello sbagliato.

Ciò accade perché Newtonsoft.Json rilascia versioni incompatibili con lo stesso nome sicuro.

Esempio:

permette di dire la nostra applicazione compilata contro NJdll (assemblaggio versione 1.0 , file di versione 1.0)

Poi qualche altra applicazione, mettere altra versione non compatibile di stessa DLL per la GAC NJdll (assemblaggio versione 1.0 , versione del file 1,1)

B perché cambiano solo la versione del file e non cambiano la versione dell'assembly, questi due assembly hanno lo stesso nome sicuro.

Quindi per la nostra applicazione .NET che tenta di risolvere N.J.dll (assembly 1.0), vede dll in GAC e lo carica. (Perché .NET preferisce sempre l'assembly da GAC ​​per l'assemblaggio dalla cartella "bin")

Ma l'assembly caricato non è corretto. Ha la versione 1.1 del file e non è compatibile con la versione 1.0.

Poiché entrambi gli assembly hanno la stessa versione di assemblaggio, .NET non vede alcuna differenza tra di loro. Ma quando tenta di risolvere qualche classe o membro all'interno, fallisce perché è stato modificato nella versione 1.1.

E l'intera applicazione non riesce con errori imprevedibili.

Quindi la mia domanda è, posso sapere come caricare prima il montaggio corretto, prima.NET carico sbagliato uno?

Aggiornamento

https://github.com/JamesNK/Newtonsoft.Json/issues/615 https://github.com/JamesNK/Newtonsoft.Json/issues/1001

Problemi con questo problema è stato chiuso con un commento che mostrano come autore di Newtonsoft.Json non capisce .NET versioni e perché questo è importante.

+2

È successo anche con Microsoft prima - J # è stato rilasciato nuovamente con la versione di assemblaggio invariata. Se lo rilevi durante l'installazione, puoi chiedere all'utente di installare la versione corretta dell'assembly in GAC. L'altra opzione è quella di produrre il proprio binario dalle stesse origini e assegnargli un nome forte come si desidera (se la licenza lo consente) – IgorK

+1

Il problema è ancora più grande. Microsoft stessa usa Newton Json.NET nelle sue librerie e SDK. Quindi qualsiasi cosa li usi potrebbe rompersi in qualsiasi momento con errori molto strani. –

+1

Questo spiega finalmente una serie di eccezioni impreviste che ho ricevuto in un'applicazione MVC web API mezzo anno fa. L'app utilizzava Json.Net con una versione superiore rispetto alla versione in bundle con WebAPI stessa. L'applicazione ha funzionato correttamente subito dopo la distribuzione, fino a quando IIS non decide di sospenderlo (dopo circa 30 minuti di mancato utilizzo). Quando qualcuno accede all'applicazione dopo la sospensione, IIS tenta di riavviarlo, ma in qualche modo mette a posto la versione di Json.Net e la mia applicazione funzionante è morta notoriamente. Non avevo Json.Net in GAC, usavo solo NuGet per gestire le mie dipendenze. –

risposta

3

Il caricatore di assiemi esegue solo la ricerca di assiemi mancanti, vale a dire assiemi che non sono già stati caricati. Se si distribuisce la DLL nella cartella di installazione dell'applicazione, caricarla in modo esplicito all'avvio dell'applicazione, quindi il caricatore dell'assieme non tenterà di caricarlo nuovamente dal GAC.

È possibile caricare l'assieme in modo esplicito utilizzando il metodo Assembly.LoadFrom.

Vedere https://msdn.microsoft.com/en-us/library/dd153782(v=vs.110).aspx per ulteriori informazioni.

+0

Sì, ma è molto difficile da raggiungere. Perché è necessario che si verifichi prima di inizializzare qualsiasi tipo che utilizza l'assembly specificato. Deve essere molto presto e non conosco nessun evento o punto di ingresso che accada in modo affidabile che presto –

+0

Che tipo di applicazione è? Si tratta di un sito Web, di un'app console ... Esiste quasi sempre un punto di avvio in cui è possibile inserire questo codice, ma in cui dipende esattamente dal tipo di applicazione. – bikeman868

+1

È anche possibile creare un'app del caricatore. L'app del caricatore creerà un nuovo dominio per app, caricherà esplicitamente le DLL per l'applicazione nel nuovo dominio dell'app prima di chiamare il punto di ingresso dell'applicazione per eseguirlo. Questa è la soluzione più estrema che possa immaginare, e non è quasi certamente necessaria per la tua situazione. – bikeman868