Pergunta

Estou tentando usar o InternalsVisibleTo Atributo da montagem para tornar minhas classes internas em uma biblioteca de classe .NET visível ao meu projeto de teste de unidade. Por alguma razão, continuo recebendo uma mensagem de erro que diz:

'MyClassName' é inacessível devido ao seu nível de proteção

Ambos os conjuntos são assinados e eu tenho a tecla correta listada na declaração de atributo. Alguma ideia?

Foi útil?

Solução

Você tem certeza absoluta de que tem a chave pública correta especificada no atributo? Observe que você precisa especificar a chave pública completa, não apenas o token da chave pública. Parece algo como:

[assembly: InternalsVisibleTo("MyFriendAssembly,
PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73
F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66
A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519
674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C140
6E2F553073FF557D2DB6C5")]

São 320 dígitos hexadecimais. Não sei por que você precisa especificar a chave pública completa - possivelmente apenas com o token de chave pública que é usada em outras referências de montagem, seria mais fácil para alguém falsificar a identidade da Assembléia de Amigos.

Outras dicas

Outro possível "Gotcha": o nome da Assembléia de Amigos que você especifica no InternalsVisibleToAttribute devo exatamente Combine o nome da Assembléia do seu amigo, conforme mostrado nas propriedades do projeto do amigo (na guia Aplicativo).

No meu caso, eu tinha um projeto Thingamajig e um projeto complementar ThingamajigAutoTests (Os nomes mudaram para proteger os culpados) que ambos produziram conjuntos não assinados. Eu adicionei devidamente o atributo [assembly: InternalsVisibleTo( "ThingamajigAutoTests" )] para o arquivo Thingamajig AssemblyInfo.cs e comentou o AssemblyKeyFile e AssemblyKeyName atributos como observado acima. o Thingamajig O Project construiu muito bem, mas seus membros internos se recusaram teimosamente a aparecer no projeto AutoTest.

Depois de muitos arranhões na cabeça, eu recobhei o ThingamajigAutoTests Propriedades do projeto, e descobriu que o nome da assembléia foi especificado como "Thingamajigautotests.dll". Bingo - eu adicionei a extensão ".dll" ao nome da montagem no InternalsVisibleTo atributo, e as peças se encaixaram.

Às vezes são as coisas mais pequenas ...

Se seus assemblies não forem assinados, mas você ainda está recebendo o mesmo erro, verifique seu arquivo AssemblyInfo.cs para uma das seguintes linhas:

[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]

A guia Propriedades ainda mostrará sua assembléia como não assinada se (ou ambas) estas linhas estiverem presentes, mas o atributo InternalalsVisibleto trata uma montagem com essas linhas como fortemente assinadas. Basta excluir (ou comentar) essas linhas, e deve funcionar bem para você.

Vale a pena notar que, se a montagem do "amigo" (testes) estiver escrito em C ++/CLI, em vez de C#/vb.net, você precisa usar o seguinte:

#using "AssemblyUnderTest.dll" as_friend

em vez de uma referência do projeto ou o usual #using declaração. Por alguma razão, não há como fazer isso na interface do usuário de referência do projeto.

Você pode usar Ferramenta de AssemblyHelper Isso gerará sintaxe internaVisibleto para você. Aqui está o link para a versão mais recente. Basta observar que ele funciona apenas para assemblies fortemente nomeados.

Aqui está uma macro que eu uso para gerar rapidamente esse atributo. É um pouco hacky, mas funciona. Na minha máquina. Quando o mais recente binário assinado está em /bin/debug. Equívoco etc. De qualquer forma, você pode ver como ela recebe a chave, para que isso dê uma dica. Corrija/melhore conforme o seu tempo permitir.

Sub GetInternalsVisibleToForCurrentProject()
    Dim temp = "[assembly:  global::System.Runtime.CompilerServices." + _
               "InternalsVisibleTo(""{0}, publickey={1}"")]"
    Dim projs As System.Array
    Dim proj As Project
    projs = DTE.ActiveSolutionProjects()
    If projs.Length < 1 Then
        Return
    End If

    proj = CType(projs.GetValue(0), EnvDTE.Project)
    Dim path, dir, filename As String
    path = proj.FullName
    dir = System.IO.Path.GetDirectoryName(path)
    filename = System.IO.Path.GetFileNameWithoutExtension(path)
    filename = System.IO.Path.ChangeExtension(filename, "dll")
    dir += "\bin\debug\"
    filename = System.IO.Path.Combine(dir, filename)
    If Not System.IO.File.Exists(filename) Then
        MsgBox("Cannot load file " + filename)
        Return
    End If
    Dim assy As System.Reflection.Assembly
    assy = System.Reflection.Assembly.Load(filename)
    Dim pk As Byte() = assy.GetName().GetPublicKey()
    Dim hex As String = BitConverter.ToString(pk).Replace("-", "")
    System.Windows.Forms.Clipboard.SetText(String.Format(temp, assy.GetName().Name, hex))
    MsgBox("InternalsVisibleTo attribute copied to the clipboard.")
End Sub

Você precisa usar o interruptor /out: compilador ao compilar a montagem de amigos (a montagem que não contém o atributo InternalalsVisibleTo).

O compilador precisa saber o nome da montagem sendo compilada para determinar se a montagem resultante deve ser considerada uma assembléia de amigos.

Além de tudo isso, quando tudo parece estar correto, mas a assembléia de amigos se recusa teimosamente a ver internos, Recarregar a solução ou reiniciar o Visual Studio pode resolver o problema.

No meu caso usando vs.net 2015, eu precisava assinar AMBAS Assembléias (se pelo menos 1 Assembléia deverá ser assinada ou você desejar fazer referência na chave pública da sua assembléia).

Meu projeto não usou a assinatura. Então, comecei a adicionar uma chave de sinal à minha biblioteca de teste e a usar o InternalnalSVisibleTo-Atribute na biblioteca base do meu projeto. Mas o vs.net sempre explicou que não podia acessar os métodos de amigos.

Quando comecei a assinar a biblioteca base (ela pode ser a mesma ou outra chave de sinal - desde que você assine a biblioteca base), o VS.NET foi imediatamente capaz de trabalhar conforme o esperado.

Respostas anteriores com o PublicKey funcionou: (Visual Studio 2015: Precisa estar em uma linha, caso contrário, reclama que a referência da Assembléia é inválida ou não pode referenciar. PublicKeyToken não funcionou)

[assembly: InternalsVisibleTo("NameSpace.MyFriendAssembly, PublicKey=0024000004800000940000000602000000240000525341310004000001000100F73F4DDC11F0CA6209BC63EFCBBAC3DACB04B612E04FA07F01D919FB5A1579D20283DC12901C8B66A08FB8A9CB6A5E81989007B3AA43CD7442BED6D21F4D33FB590A46420FB75265C889D536A9519674440C3C2FB06C5924360243CACD4B641BE574C31A434CE845323395842FAAF106B234C2C1406E2F553073FF557D2DB6C5")]

Obrigado a @joe

Para obter a chave pública da Assembléia de Amigos:

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

Dentro de um prompt de comando de desenvolvimento (Startup> Programas> Visual Studio 2015> Visual Studio Tools> Developer Command Prompt para vs2015). Obrigado a @ian G.

Embora o toque final que o fez funcionar para mim depois que o exposto foi assinar o projeto da biblioteca da minha amiga da mesma maneira que o projeto da biblioteca para compartilhar é assinado. Como era uma nova biblioteca de testes, ainda não estava assinada.

Você é obrigado a gerar uma nova chave pública completa para a assembléia e, em seguida, especificar o atributo à montagem.

[assembly: InternalsVisibleTo("assemblyname,
PublicKey="Full Public Key")]

Siga o abaixo Msdn Etapas para gerar nova chave pública completa para a assembléia do Visual Studio.

Para adicionar um item de chave pública de Assembly ao menu Ferramentas

No Visual Studio, clique Ferramentas externas no menu Ferramentas.

Na caixa de diálogo Ferramentas externas, clique Adicionar e digite a chave pública Get Assembly na caixa de título.

Preencha a caixa de comando navegando para sn.exe. Normalmente é instalado no seguinte local: C: Arquivos de programas (x86) Microsoft SDKS Windows V7.0a bin x64 sn.exe.

Na caixa de argumentos, digite o seguinte (sensível ao caso): -TP $ (TargetPath). Selecione a caixa de seleção da janela de saída de saída.

Clique OK. O novo comando é adicionado ao menu Ferramentas.

Sempre que você precisar do token da chave pública da Assembléia, está desenvolvendo, clique no comando Get Assembly Public Key no menu Ferramentas e o token de chave público aparece na janela de saída.

Outra possibilidade que pode ser complicada de rastrear, dependendo de como seu código é escrito.

  1. Você está invocando um método interno definido em x de outra montagem y
  2. A assinatura do método usa tipos internos definidos em z
  3. Você então precisa adicionar [InternalnalSVisibleTo] em x e em z z

Por exemplo:

// In X
internal static class XType
{
    internal static ZType GetZ() { ... }
}

// In Y:
object someUntypedValue = XType.GetZ();

// In Z:
internal class ZType { ... }

Se você o tiver escrito acima, onde não está se referindo ao ZType diretamente em Y, depois de ter adicionado Y como amigo de X, você pode ficar confuso por que seu código ainda não compilar.

O erro de compilação poderia definitivamente ser mais útil neste caso.

Aplica -se apenas se você deseja manter as montagens não assinadas como montagem não assinada (e não quiser assinar por vários motivos):

Ainda há outro ponto: se você compilar sua biblioteca base do vs.NET a um diretório local, ele poderá funcionar conforme o esperado.

Mas: assim que você compilar sua biblioteca base em uma unidade de rede, as políticas de segurança se aplicam e a montagem não pode ser carregada com sucesso. Isso novamente faz com que o vs.NET ou o compilador falhem ao verificar a partida do PublicKey.

Finalmente, é possível usar conjuntos não assinados:https://msdn.microsoft.com/en-us/library/bb384966.aspxVocê deve garantir que ambos os conjuntos não sejam assinados e que o atributo da Assembléia deve estar sem informações de chave pública:

<Assembly: InternalsVisibleTo("friend_unsigned_B")>

Estou escrevendo isso por frustração. Certifique -se de que a Assembléia a que você está concedendo ao acesso seja nomeada como você espera.

Renomeei meu projeto, mas isso não atualiza automaticamente o nome da montagem. Clique com o botão direito do mouse no seu projeto e clique Propriedades. Debaixo Inscrição, verifique se o Nome da montagem e Namespace padrão são o que você espera.

Eu tive o mesmo problema. Nenhuma das soluções funcionou.

Eventualmente descobriu que o problema foi devido à implementação explicitamente da classe X, que é interna.

O método x.interfacemethod não estava disponível, embora eu não tenha idéia do porquê.

A solução foi lançar (x como seu interface) .Interfacemethod na biblioteca de testes e, em seguida, as coisas funcionaram.

Como nota lateral, se você deseja obter facilmente a chave pública sem ter que usar o SN e descobrir suas opções, você pode baixar o programa útil aqui. Ele não apenas determina a chave pública, mas também cria a linha "Assembléia: InternalnalsVisibleto ..." pronta para ser copiada para a área de transferência e colada no seu código.

Acabei de resolver um problema semelhante com o InternalsVisibleTo Atributo. Tudo parecia certo e eu não conseguia descobrir por que a classe interna que eu estava apontando ainda não estava acessível.

Alterar o caso da chave da parte superior para a minúscula corrigida o problema.

Se você tiver mais de 1 Assembléia referenciada - verifique se todos os assemblies necessários possuem atributo InternalalsVisibleTo. Às vezes, não é obviamente, e nenhuma mensagem que você precisa adicionar esse atributo a outra montagem.

1- Assine o projeto de teste: No Visual Studio, vá para a janela de propriedades de o projeto de teste e Assine a montagem verificando a caixa de seleção com a mesma frase no Assinatura aba.

2- Crie uma chave pública para o projeto de teste: Open Visual Studio Command Prompt (por exemplo, prompt de comando do desenvolvedor para vs 2017). Vá para a pasta onde o arquivo .dll de o projeto de teste existe. Crie uma chave pública via Sn.exe:

SN -TP testProject.dll

Observe que o argumento é -tp, mas não -tp.

3- Apresente o PublicKey ao projeto a ser testado: Vá para o arquivo de AssemblyInfo.cs o projeto a ser testado e adicione esta linha com o PublicKey criado na etapa anterior:

Assembléia: InternalnalSvisibleto ("TestProjectASSEMBLYNAME, Chave pública=2066212d128683a85f31645c60719617ba512c0bfdba6791612ed56350368f6cc40a17b4942ff16cda9e760684658fa3f357c137a1005b04cb002400000480000094000000060200000024000052534131000400000100010065fe67a14eb30ffcdd99880e9d725f04e5c720dffc561b23e2953c34db8b7c5d4643f476408ad1b1e28d6bde7d64279b0f51bf0e60be2d383a6c497bf27307447506b746bd2075")

Não se esqueça de substituir a chave pública acima pela sua.

4- Torne o método privado interno: No projeto a ser testado, altere o modificador de acesso do método para interno.

estática interna void Dosomething () {...}

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top