Diferença entre LoadFile e LoadFrom com assemblies .NET?

126

Eu estava olhando a documentação do msdn e ainda estou um pouco confuso sobre qual é exatamente a diferença entre usar LoadFilee LoadFromcarregar um assembly. Alguém pode fornecer um exemplo ou uma analogia para melhor descrevê-lo. A documentação do MSDN me confundiu mais. Além disso, é ReflectionOnlyLoadFromo mesmo que LoadFromexceto que ele carrega a montagem apenas no modo de reflexão.

Como minha experiência em .NET não é a melhor, aqui estão algumas perguntas sobre a documentação do MSDN usando o LoadFile:

1) O que significa LoadFileexaminar assembléias com a mesma identidade, mas localizadas em caminhos diferentes? Qual é a identidade (exemplo)?

2) Ele afirma LoadFileque não carrega arquivos no 'Contexto LoadFrom' e não resolve dependências usando o caminho de carregamento. O que isso significa, alguém pode dar um exemplo?

3) Por fim, afirma que LoadFileé útil nesse cenário limitado porque o LoadFrom não pode carregar assemblies que tenham as mesmas identidades, mas caminhos diferentes; ele carregará apenas o primeiro assembly, o que novamente me leva à mesma pergunta: qual é a identidade dos assemblies?

Xaisoft
fonte
10
Seriamente eu também acho que às vezes que MS deve contratar melhores escritores ou qualquer outra coisa desde que as frases nem sempre são compreensíveis ...
Tarik
7
Veja também não- documentação
Coronel Panic
1
@ColonelPanic MS pode dizer que tudo está documentado ... mas com um fator de ajuda de zeroooo.
Legends

Respostas:

96

Isso esclarece?

// 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 às perguntas que você levantou na sua pergunta revisada, você definitivamente quer ler Suzanne Cook sobre Assembly Identity .

Existem muitas regras que governam como os assemblies são carregados e alguns deles têm a ver com a maneira como resolvem dependências - se o AssemblyA é dependente do AssemblyB, onde o .NET deve procurar o AssemblyB? No Global Assembly Cache, o mesmo diretório que encontrou AssemblyA, ou em algum outro lugar inteiramente? Além disso, se encontrar várias cópias dessa montagem, como escolher qual usar?

LoadFromtem um conjunto de regras, enquanto LoadFiletem outro conjunto de regras. É difícil imaginar muitas razões para usar LoadFile, mas se você precisar usar a reflexão em diferentes cópias da mesma montagem, está lá para você.

Jeff Sternal
fonte
2
O CodeBase é o mesmo que a identidade?
Xaisoft
Não, eu apenas usei o CodeBase aqui como uma propriedade arbitrária do assembly para ilustrar que a segunda instância do Assembly estava apontando para o arquivo 'errado' (no primeiro exemplo). Estou atualizando minha resposta com mais detalhes.
Jeff Sternal
1
Isso esclarece um pouco, mas como o path1 e o path2 apontam para cópias diferentes do mesmo assembly no disco ao usar o LoadFrom e ao usar o LoadFile, o path1 e o path2 apontam para diferentes assemblies. Qual é um exemplo de qual caminho1 e caminho2 seria? Obrigado pela sua paciência.
Xaisoft 25/09/2009
Por que você verifica duas referências de string para igualdade de valor string.Compare(x, y) == 0? Eu acho que você quer x == ylá? Se por motivos obscuros você deseja uma verificação de igualdade dependente da cultura, é mais claro escrever string.Equals(x, y, StringComparison.CurrentCulture), por exemplo.
Jeppe Stig Nielsen
@JeffSternal Fazer a ligação em "Suzanne Cozinhe em Assembleia Identidade" parece estar quebrado aqui ...
Martin Verjans
61

Do blog de Suzanne Cook :

LoadFile vs. LoadFrom

Tenha cuidado - estes não são a mesma coisa.

LoadFrom () passa pelo Fusion e pode ser redirecionado para outro assembly em um caminho diferente, mas com a mesma identidade se um já estiver carregado no contexto LoadFrom.

O LoadFile () não se liga ao Fusion - o carregador apenas avança e carrega exatamente * o que o chamador solicitou. Ele não usa o contexto Load ou LoadFrom.

Portanto, o LoadFrom () geralmente fornece o que você pediu, mas não necessariamente. LoadFile () é para quem realmente quer exatamente o que é solicitado. (* No entanto, a partir da v2, a política será aplicada a LoadFrom () e LoadFile (), portanto, LoadFile () não será necessariamente exatamente o que foi solicitado. Além disso, a partir da v2, se um assembly com sua identidade estiver em no GAC, a cópia do GAC será usada. Use ReflectionOnlyLoadFrom () para carregar exatamente o que você deseja - mas observe que os assemblies carregados dessa maneira não podem ser executados.

LoadFile () tem um problema. Como ele não usa um contexto de ligação, suas dependências não são encontradas automaticamente em seu diretório. Se eles não estiverem disponíveis no contexto Carregar, você precisará se inscrever no evento AssemblyResolve para vincular a eles.

Veja aqui .

Consulte também Escolhendo um artigo de contexto de ligação no mesmo blog.

CraigTP
fonte
Obrigado, vou verificar o blog, atualizei meu post com algumas perguntas sobre a documentação do msdn.
Xaisoft 25/09/09
@Xaisoft - O blog de Suzanne Cook volta ao resgate com a resposta de uma identidade de assembléias. Consulte blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx . É essencialmente um "nome para exibição do assembly" e é algo como: "Sistema, Versão = 1.0.3300.0, Culture = neutral, PublicKeyToken = b77a5c561934e089", portanto, inclui o nome real do assembly, o número da versão e outras informações de identificação (como PublicKeyToken etc.).
CraigTP
1
A que ela está se referindo quando fala sobre o Fusion?
Xaisoft 25/09/09
1
Na verdade, Jeff está no local. Veja este link: grimes.demon.co.uk/workshops/fusionWS.htm para obter um bom tutorial sobre o subsistema Fusion e sua tecnologia para carregar assemblies no .NET
CraigTP
1
Apenas uma atualização rápida, observe que o URL acima (grimes.demon.co.uk/workshops/fusionWS.htm) não é mais válido e agora foi movido para: richardgrimes.com/workshops/fusionWS.htm
CraigTP
45

Depois de muito coçar a cabeça, descobri uma diferença esta tarde.

Eu queria carregar uma DLL em tempo de execução, e a DLL residia em outro diretório. Essa DLL tinha suas próprias dependências (DLLs), que também residiam no mesmo diretório.

LoadFile (): carregou a DLL específica, mas não as dependências. Portanto, quando a primeira chamada foi feita de dentro da DLL para uma dessas outras DLLs, lançou um FileNotFoundException.

LoadFrom (): carregou a DLL que especifiquei e também todas as dependências que viviam nesse diretório.

LordWilmore
fonte
4
Esse foi exatamente o meu problema! Eu estava recebendo a FileNotFoundExceptionmensagem ao criar uma nova instância de um objeto definido em um assembly referenciado pelo assembly que eu acabei de carregar .LoadFile. Alterar isso para .LoadFromapareceu para corrigir o problema, mas eu não sabia o porquê! Obrigado
Connell
1
Obrigado, eu estava tendo o mesmo problema.
Ivandro IG Jao 25/11
4

Nota: Se um assembly for carregado usando um caminho 8.3 e, a partir de um caminho não-8.3, eles serão vistos como conjuntos diferentes, mesmo que sejam a mesma DLL física.

Gregg DeMasters
fonte
0

uma diferença que eu notei é:

Assembly.LoadFile - Carrega o assembly no AppDomain diferente, com direitos de usuário limitados (princípio da diferença). operações como serilização / desserilização não puderam ser executadas.

Assembly.LoadFrom - Carrega o assembly no mesmo AppDomain com os mesmos direitos de usuário (mesmo princípio).

Lalit
fonte
3
Isso não está correto. O que faz você acreditar que Assembly.LoadFile carrega um assembly em outro AppDomain?
fr34kyn01535
0

No meu caso, eu apenas tive que excluir o cache do aplicativo ASP localizado @ C:\Windows\Microsoft.NET\Framework\[asp version]\Temporary ASP.NET Files. É reconstruído quando o site é executado pela primeira vez. Certifique-se de parar o IIS primeiro.

Espero que isso ajude alguém como fez por mim.

David Roth
fonte