¿Diferencia entre LoadFile y LoadFrom con .NET Assemblies?

126

Estaba mirando la documentación de msdn y todavía estoy un poco confundido sobre cuál es exactamente la diferencia entre usar LoadFiley LoadFromal cargar un ensamblaje. ¿Alguien puede proporcionar un ejemplo o una analogía para describirlo mejor? La documentación de MSDN me confundió más. Además, es ReflectionOnlyLoadFromigual que LoadFromexcepto que carga el ensamblaje solo en modo de reflexión.

Dado que mi experiencia .NET no es la mejor, aquí hay algunas preguntas sobre la documentación de MSDN con LoadFile:

1) ¿Qué significa LoadFileexaminar asambleas que tienen la misma Identidad, pero están ubicadas en diferentes rutas? ¿Cuál es la identidad (ejemplo)?

2) Establece LoadFileque no carga archivos en el 'Contexto LoadFrom' y no resuelve dependencias usando la ruta de carga. ¿Qué significa esto, alguien puede dar un ejemplo?

3) Por último, afirma que LoadFilees útil en este escenario limitado porque LoadFrom no puede cargar ensamblajes que tienen las mismas identidades pero diferentes rutas; solo cargará el primer conjunto de este tipo, lo que nuevamente me lleva a la misma pregunta, ¿cuál es la identidad de los conjuntos?

Xaisoft
fuente
10
En serio, también creo que a veces la EM debería contratar mejores escritores o algo más, ya que las oraciones no siempre son comprensibles ...
Tarik
77
Ver también indocumentación
Coronel Panic
1
@ColonelPanic MS puede decir que todo está documentado ... pero con un factor de ayuda de zeroooo.
Leyendas

Respuestas:

96

¿Esto lo aclara?

// 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);

Editar : para responder las preguntas que planteó en su pregunta revisada, definitivamente desea leer a Suzanne Cook sobre Identidad de la Asamblea .

Hay muchas reglas que rigen cómo se cargan los ensamblajes, y algunos de ellos tienen que ver con cómo resuelven las dependencias. En la Caché de ensamblados global, ¿el mismo directorio que encontró Ensamblado A, o en otro lugar completamente diferente? Además, si encuentra varias copias de ese ensamblaje, ¿cómo debería elegir cuál usar?

LoadFromtiene un conjunto de reglas, mientras que LoadFiletiene otro conjunto de reglas. Es difícil imaginar muchas razones para usar LoadFile, pero si necesita usar la reflexión en diferentes copias del mismo ensamblaje, está ahí para usted.

Jeff Sternal
fuente
2
¿CodeBase es lo mismo que Identity?
Xaisoft
No, acabo de usar CodeBase aquí como una propiedad arbitraria del ensamblado para ilustrar que la segunda instancia de ensamblado apuntaba al archivo 'incorrecto' (en el primer ejemplo). Estoy actualizando mi respuesta con más detalles.
Jeff Sternal
1
Lo aclara un poco, pero cómo la ruta1 y la ruta2 apuntan a diferentes copias del mismo ensamblaje en el disco cuando se usa LoadFrom y cuando se usa LoadFile, la ruta1 y la ruta2 apuntan a ensamblajes diferentes. ¿Cuál es un ejemplo de lo que serían path1 y path2? Gracias por su paciencia.
Xaisoft
¿Por qué verifica dos referencias de cadena para la igualdad de valores con string.Compare(x, y) == 0? Creo que quieres x == yallí? Si, por razones oscuras, desea un control de igualdad dependiente de la cultura, es más claro escribir string.Equals(x, y, StringComparison.CurrentCulture), por ejemplo.
Jeppe Stig Nielsen
El enlace de @JeffSternal en "Suzanne Cook sobre la identidad de la asamblea" parece estar roto aquí ...
Martin Verjans
61

Del blog de Suzanne Cook :

LoadFile vs. LoadFrom

Ten cuidado, no son lo mismo.

LoadFrom () pasa por Fusion y se puede redirigir a otro ensamblado en una ruta diferente pero con la misma identidad si ya se ha cargado uno en el contexto LoadFrom.

LoadFile () no enlaza a través de Fusion en absoluto: el cargador simplemente continúa y carga exactamente * lo que solicitó la persona que llama. No utiliza el contexto Load o LoadFrom.

Por lo tanto, LoadFrom () generalmente le brinda lo que solicitó, pero no necesariamente. LoadFile () es para aquellos que realmente quieren exactamente lo que se solicita. (* Sin embargo, a partir de la v2, la política se aplicará tanto a LoadFrom () como a LoadFile (), por lo que LoadFile () no será necesariamente exactamente lo que se solicitó. Además, a partir de la v2, si un ensamblado con su identidad está en el GAC, la copia del GAC se usará en su lugar. Use ReflectionOnlyLoadFrom () para cargar exactamente lo que desea, pero tenga en cuenta que los ensamblados cargados de esa manera no se pueden ejecutar).

LoadFile () tiene un problema. Como no utiliza un contexto vinculante, sus dependencias no se encuentran automáticamente en su directorio. Si no están disponibles en el contexto Cargar, deberá suscribirse al evento AssemblyResolve para enlazarlos.

Ver aquí .

Consulte también el artículo Elección de un contexto vinculante en el mismo blog.

CraigTP
fuente
Gracias, revisaré el blog, actualicé mi publicación con algunas preguntas sobre la documentación de msdn.
Xaisoft
@Xaisoft: el blog de Suzanne Cook vuelve al rescate nuevamente con la respuesta de una identidad de asambleas. Ver blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx . Es esencialmente un "nombre para mostrar del ensamblado" y es algo así como: "Sistema, Versión = 1.0.3300.0, Cultura = neutral, PublicKeyToken = b77a5c561934e089", por lo que incluye tanto el nombre real del ensamblaje como el número de versión junto con otra información de identificación (como PublicKeyToken, etc.).
CraigTP
1
¿A qué se refiere cuando habla de Fusion?
Xaisoft
1
De hecho, Jeff es perfecto. Consulte este enlace: grimes.demon.co.uk/workshops/fusionWS.htm para obtener un buen tutorial sobre el subsistema Fusion y su tecnología para cargar ensamblajes en .NET
CraigTP
1
Solo una actualización rápida, tenga en cuenta que la URL anterior (grimes.demon.co.uk/workshops/fusionWS.htm) ya no es válida y ahora se ha movido a: richardgrimes.com/workshops/fusionWS.htm
CraigTP
45

Después de mucho rascarme la cabeza, he descubierto una diferencia esta tarde.

Quería cargar una DLL en tiempo de ejecución, y la DLL vivía en otro directorio. Esa DLL tenía sus propias dependencias (DLL) que también vivían en ese mismo directorio.

LoadFile (): cargó la DLL específica, pero no las dependencias. Entonces, cuando se realizó la primera llamada desde la DLL a una de esas otras DLL, arrojó una excepción FileNotFoundException.

LoadFrom (): cargó la DLL que especifiqué y también todas las dependencias que vivían en ese directorio.

LordWilmore
fuente
44
Ese fue exactamente mi problema! Estaba obteniendo el FileNotFoundExceptioncuando creaba una nueva instancia de un objeto definido en un ensamblaje al que hacía referencia el ensamblaje con el que acababa de cargar .LoadFile. Cambiando esto a .LoadFromparece que soluciona el problema, ¡pero no sabía por qué! Gracias
Connell
1
Gracias, estaba teniendo el mismo problema.
Ivandro IG Jao
4

Nota: Si se carga un ensamblaje utilizando una ruta 8.3 y luego desde una ruta que no sea 8.3, se verán como ensamblajes diferentes, aunque sean la misma DLL física.

Gregg DeMasters
fuente
0

Una diferencia que noté es:

Assembly.LoadFile : carga el ensamblaje en diferentes AppDomain con derechos de usuario limitados (principio de diferencia). operaciones como la serilización / deserilización no se pudieron realizar.

Assembly.LoadFrom : carga el ensamblaje en el mismo AppDomain con los mismos derechos de usuario (mismo principio).

Lalit
fuente
3
Esto no es correcto. ¿Qué te hace creer que Assembly.LoadFile carga un ensamblado en otro AppDomain?
fr34kyn01535
0

En mi caso, solo tuve que eliminar simplemente la caché de la aplicación ASP ubicada @ C:\Windows\Microsoft.NET\Framework\[asp version]\Temporary ASP.NET Files. Se reconstruye cuando el sitio se ejecuta por primera vez. Asegúrese de detener IIS primero.

Espero que esto ayude a alguien como lo hizo por mí.

David Roth
fuente