Différence entre LoadFile et LoadFrom avec les assemblys .NET?

126

Je regardais la documentation msdn et je ne sais toujours pas quelle est exactement la différence entre l'utilisation LoadFileet le LoadFromchargement d'un assemblage. Quelqu'un peut-il donner un exemple ou une analogie pour mieux le décrire. La documentation MSDN m'a encore plus troublé. En outre, est ReflectionOnlyLoadFromle même que LoadFromsauf qu'il charge l'assemblage uniquement en mode réflexion.

Étant donné que mon expérience .NET n'est pas la meilleure, voici quelques questions concernant la documentation MSDN utilisant LoadFile:

1) Que signifie LoadFileexaminer les assemblys qui ont la même identité, mais sont situés dans des chemins différents? Quelle est l'identité (exemple)?

2) Il indique LoadFileque ne charge pas les fichiers dans le 'Contexte LoadFrom' et ne résout pas les dépendances en utilisant le chemin de chargement. Qu'est-ce que cela signifie, quelqu'un peut-il donner un exemple?

3) Enfin, il déclare que cela LoadFileest utile dans ce scénario limité car LoadFrom ne peut pas charger des assemblys qui ont les mêmes identités mais des chemins différents; il ne chargera que la première de ces assemblées, ce qui m'amène à nouveau à la même question, quelle est l'identité des assemblées?

Xaisoft
la source
10
Sérieusement, je pense aussi parfois que MS devrait embaucher de meilleurs écrivains ou autre chose car les phrases ne sont pas toujours compréhensibles ...
Tarik
7
Voir aussi sans documentation
Colonel Panic
1
@ColonelPanic MS peut dire que tout est documenté ... mais avec un facteur d'aide de zeroooo.
Legends

Réponses:

96

Est-ce que cela clarifie les choses?

// path1 and path2 point to different copies of the same assembly on disk:

Assembly assembly1 = Assembly.LoadFrom(path1);
Assembly assembly2 = Assembly.LoadFrom(path2);

// These both point to the assembly from path1, so this is true
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

assembly1 = Assembly.LoadFile(path1);
assembly2 = Assembly.LoadFile(path2);

// These point to different assemblies now, so this is false
Console.WriteLine(assembly1.CodeBase == assembly2.CodeBase);

Edit : pour répondre aux questions que vous avez soulevées dans votre question révisée, vous voulez absolument lire Suzanne Cook sur l'identité de l'assemblée .

Il existe de nombreuses règles qui régissent la façon dont les assemblys sont chargés, et certaines d'entre elles ont à voir avec la façon dont ils résolvent les dépendances - si votre AssemblyA dépend de AssemblyB, où .NET doit-il rechercher AssemblyB? Dans le Global Assembly Cache, le même répertoire où il a trouvé AssemblyA, ou ailleurs entièrement? De plus, s'il trouve plusieurs copies de cet assemblage, comment devrait-il choisir lequel utiliser?

LoadFroma un ensemble de règles, tandis LoadFilequ'un autre ensemble de règles. Il est difficile d'imaginer de nombreuses raisons à utiliser LoadFile, mais si vous deviez utiliser la réflexion sur différentes copies du même assemblage, elle est là pour vous.

Jeff Sternal
la source
2
Le CodeBase est-il le même que l'identité?
Xaisoft
Non, je viens d'utiliser CodeBase ici comme propriété arbitraire de l'assembly pour illustrer que la deuxième instance de l'assembly pointait vers le `` mauvais '' fichier (dans le premier exemple). Je mets à jour ma réponse avec plus de détails.
Jeff Sternal
1
Cela clarifie un peu les choses, mais comment path1 et path2 pointent vers des copies différentes du même assembly sur le disque lors de l'utilisation de LoadFrom et lors de l'utilisation de LoadFile, path1 et path2 pointent vers des assemblys différents. Quel est un exemple de ce que seraient path1 et path2? Merci pour votre patience.
Xaisoft
Pourquoi vérifiez-vous deux références de chaîne pour l'égalité des valeurs avec string.Compare(x, y) == 0? Je pense que tu veux x == ylà? Si, pour des raisons obscures, vous voulez un contrôle d'égalité dépendant de la culture, il est plus clair d'écrire string.Equals(x, y, StringComparison.CurrentCulture), par exemple.
Jeppe Stig Nielsen
@JeffSternal Link sur "Suzanne Cook on Assembly Identity" semble être rompu ici ...
Martin Verjans
61

Du blog de Suzanne Cook :

LoadFile et LoadFrom

Soyez prudent - ce ne sont pas la même chose.

LoadFrom () passe par Fusion et peut être redirigé vers un autre assembly sur un chemin différent mais avec la même identité si l'un est déjà chargé dans le contexte LoadFrom.

LoadFile () ne se lie pas du tout via Fusion - le chargeur continue et charge exactement * ce que l'appelant a demandé. Il n'utilise ni le contexte Load ni le contexte LoadFrom.

Ainsi, LoadFrom () vous donne généralement ce que vous avez demandé, mais pas nécessairement. LoadFile () est pour ceux qui veulent vraiment, vraiment exactement ce qui est demandé. (* Cependant, à partir de la v2, la stratégie sera appliquée à la fois à LoadFrom () et LoadFile (), donc LoadFile () ne sera pas nécessairement exactement ce qui a été demandé. De plus, à partir de la v2, si un assembly avec son identité est dans le GAC, la copie GAC sera utilisée à la place. Utilisez ReflectionOnlyLoadFrom () pour charger exactement ce que vous voulez - mais notez que les assemblys chargés de cette façon ne peuvent pas être exécutés.)

LoadFile () a une capture. Puisqu'il n'utilise pas de contexte de liaison, ses dépendances ne sont pas automatiquement trouvées dans son répertoire. S'ils ne sont pas disponibles dans le contexte de chargement, vous devez vous abonner à l'événement AssemblyResolve pour pouvoir s'y lier.

Regardez ici .

Consultez également l'article Choisir un contexte de liaison sur le même blog.

CraigTP
la source
Merci, je vais consulter le blog, j'ai mis à jour mon message avec quelques questions concernant la documentation msdn.
Xaisoft
@Xaisoft - Le blog de Suzanne Cook vient à nouveau à la rescousse avec la réponse d'une identité d'assemblées. Voir blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx . Il s'agit essentiellement d'un "nom d'affichage d'assembly" et c'est quelque chose comme: "System, Version = 1.0.3300.0, Culture = neutral, PublicKeyToken = b77a5c561934e089" comprend donc à la fois le nom réel de l'assembly, son numéro de version ainsi que d'autres informations d'identification (comme PublicKeyToken etc.).
CraigTP
1
À quoi fait-elle référence lorsqu'elle parle de Fusion?
Xaisoft
1
En effet, Jeff est parfait. Voir ce lien: grimes.demon.co.uk/workshops/fusionWS.htm pour un joli tutoriel sur le sous-système Fusion et sa technologie pour charger les assemblys dans .NET
CraigTP
1
Juste une mise à jour rapide, notez que l'URL ci-dessus (grimes.demon.co.uk/workshops/fusionWS.htm) n'est plus valide et est maintenant déplacée vers: richardgrimes.com/workshops/fusionWS.htm
CraigTP
45

Après avoir beaucoup gratté la tête, j'ai moi-même découvert une différence cet après-midi.

Je voulais charger une DLL au moment de l'exécution, et la DLL vivait dans un autre répertoire. Cette DLL avait ses propres dépendances (DLL) qui vivaient également dans ce même répertoire.

LoadFile (): a chargé la DLL spécifique, mais pas les dépendances. Ainsi, lorsque le premier appel a été effectué à partir de la DLL vers l'une de ces autres DLL, il a lancé une FileNotFoundException.

LoadFrom (): a chargé la DLL que j'ai spécifiée ainsi que toutes les dépendances qui vivaient dans ce répertoire.

LordWilmore
la source
4
C'était exactement mon problème! J'obtenais le FileNotFoundExceptionlors de la création d'une nouvelle instance d'un objet défini dans un assembly référencé par l'assembly que je venais de charger .LoadFile. Changer cela .LoadFromsemble résoudre le problème, mais je ne savais pas pourquoi! Merci
Connell
1
Merci, j'avais le même problème.
Ivandro IG Jao
4

Remarque: Si un assembly est chargé à l'aide d'un chemin 8.3, puis à partir d'un chemin non 8.3, ils seront considérés comme des assemblys différents, même s'il s'agit de la même DLL physique.

Gregg DeMasters
la source
0

une différence que j'ai remarquée est:

Assembly.LoadFile - Charge l'assembly dans différents AppDomain avec des droits d'utilisateur limités (principe de différence). des opérations telles que la sérilisation / déserilisation n'ont pas pu être effectuées.

Assembly.LoadFrom - Charge l'assembly dans le même AppDomain avec les mêmes droits d'utilisateur (même principel).

Lalit
la source
3
Ce n'est pas correct. Qu'est-ce qui vous fait croire que Assembly.LoadFile charge un assembly dans un autre AppDomain?
Sven Mawby
0

Dans mon cas, je devais simplement supprimer le cache de l'application ASP situé @ C:\Windows\Microsoft.NET\Framework\[asp version]\Temporary ASP.NET Files. Il est reconstruit lors de la première exécution du site. Assurez-vous d'abord d'arrêter IIS.

J'espère que cela aide quelqu'un comme ça l'a fait pour moi.

David Roth
la source