Como declarar uma montagem de amigo?

114

Tenho 2 projetos em minha solução:

  1. Montagem (Biblioteca Básica)
  2. Conjunto de teste (NUnit)

Eu havia declarado a montagem de teste como montagem de amigos no primeiro projeto:

[assembly: InternalsVisibleTo ("Company.Product.Tests")]

Tudo estava funcionando bem até que percebi que esqueci de configurar a solução para assinar minhas montagens. Então criei um arquivo snk e configurei o projeto do Visual Studio para assinar a primeira montagem (Biblioteca Básica). Agora, quando compilo o primeiro projeto, recebo o seguinte erro:

A referência do assembly amigo 'Company.Product.Tests' é inválida. Os assemblies assinados de nome forte devem especificar uma chave pública em suas declarações InternalsVisibleTo.

Tentei extrair a chave pública do meu arquivo snk usando o utilitário sn, mas ele gera um arquivo binário com fio que não tenho certeza de como usar. Como posso resolver o problema?

Hemant
fonte

Respostas:

194

Você precisa assinar os dois assemblies, porque efetivamente ambos os assemblies referenciam um ao outro.

Você deve colocar a chave pública no atributo InternalsVisibleTo. Por exemplo, em Buffers de protocolo, eu uso:

[assembly:InternalsVisibleTo("Google.ProtocolBuffers.Test,PublicKey="+
"00240000048000009400000006020000002400005253413100040000010001008179f2dd31a648"+
"2a2359dbe33e53701167a888e7c369a9ae3210b64f93861d8a7d286447e58bc167e3d99483beda"+
"72f738140072bb69990bc4f98a21365de2c105e848974a3d210e938b0a56103c0662901efd6b78"+
"0ee6dbe977923d46a8fda18fb25c65dd73b149a5cd9f3100668b56649932dadd8cf5be52eb1dce"+
"ad5cedbf")]

A chave pública é recuperada executando

sn -Tp path\to\test\assembly.dll

Como alternativa, obtenha-o do arquivo .snk:

sn -p MyStrongnameKey.snk public.pk
sn -tp public.pk
Jon Skeet
fonte
7
E é extremamente irritante ver a documentação do MSDN ( msdn.microsoft.com/en-us/library/… ) mencionar uma chave pública ridiculamente curta que quase parece um token de chave pública para mim.
Hemant
3
Você pode extrair a chave pública diretamente de um arquivo .snk: sn -k MyStrongnameKey.snk // sn -p MyStrongnameKey.snk public.pk // sn -tp public.pk //
Tim Long
1
Eu estava usando o 'título da montagem' especificado em AssemblyInfo.cs . Desde então, deduziu que o nome correto a ser usado é o 'nome do assembly' da caixa de diálogo Propriedades / Aplicativo do projeto (que difere novamente do nome do projeto no explorador de solução do Visual Studio).
Coronel Panic de
7
Por mais úteis que essas respostas e comentários tenham sido, eu precisava de alguns experimentos para perceber que a chave pública é aquela do assembly que contém os testes, NÃO o assembly que contém a declaração 'InternalsInvisibleTo'.
Andreas
3
@Andreas: Bem, vai junto com o assembly que você está nomeando - você está especificando o nome forte do assembly a ser confiável, dentro do assembly que está fazendo a confiança.
Jon Skeet
-3

Você pode obter publicKey diretamente do assembly de seu interesse, sem mágica com sn.exe

<!-- language: c# -->
var assemblyName = Assembly.GetExecutingAssembly().GetName();
Console.WriteLine("{0}, PublicKey={1}",
    assemblyName.Name,
string.Join("", assemblyName.GetPublicKey().Select(m => string.Format("{0:x2}", m))));
Ezyuzin
fonte
1
Esta não é uma resposta a esta pergunta. Deve ser um comentário sobre a resposta a que se dirige
Cole Johnson
-7

Acho que você precisa colocar o nome forte, que seria algo como "Company.Product.Tests, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = 17135d9fcba0119f". Presumo que Company.Product.Tests seja o nome do assembly e 17135d9fcba0119f é a chave pública.

Outra maneira de resolver esse problema seria não usar assemblies separados. Normalmente coloco o código-fonte e o código de teste no mesmo assembly. Não sei se você tem alguma preocupação especial de separá-los.

user95319
fonte
Eu não acho que precisamos especificar o número da versão e cultura (consulte msdn.microsoft.com/en-us/library/… ). Eu realmente não tentei colocar o código de teste no próprio assembly. Vou tentar ver como funciona (1 para a dica).
Hemant
4
Para InternalsVisibleTo, PublicKeToken não é suficiente. Você precisa de toda a chave pública :-(
Sean Reilly