9

I am trying to expose some internals to my unit test project by using:

[assembly: InternalsVisibleTo("MyTest")]

But I am getting the error:

Error 1 Friend assembly reference MyTest' is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations. .../MyClass.cs...

When I assign a PublicTokenKey manually:

[assembly: InternalsVisibleTo("MyTest, PublicKeyToken=XxxxxYysakf")]

The solution builds without any error.

  1. Why do I need to include a public key token?
  2. I am not sure if I will break something in production by including the public key token.

So, what is the best and safest way to assign an public key to my Test project?

Jonathan Dickinson
  • 9,050
  • 1
  • 37
  • 60
pencilCake
  • 51,323
  • 85
  • 226
  • 363
  • You shouldnt need to assign a public key token. But you need to make sure that the assembly names match. –  Aug 25 '11 at 13:44
  • I am copy pasting the assembly names from the Assembly Name field shown in Project properties. So it should be correct, I gues.. – pencilCake Aug 25 '11 at 13:59
  • Alright, so i havent encountered that issue myself, but this guy here might have another option for you http://blog.tylerholmes.com/2008/04/unit-tests-and-internalsvisibleto.html –  Aug 25 '11 at 14:01
  • The solution builds without errors when you use PublicKeyToken, but Intellisense might give you a hint that the assembly reference couldn't be resolved. – Bogdan Verbenets Aug 09 '17 at 12:53

1 Answers1

7

I am surprised that PublicKeyToken even works - on my machine it forces me to use PublicKey

  1. The reason that you need a public key token is because strongly-named assemblies can be put into the GAC - which has high trust. It would be a security hole if any assembly called 'MyTest' (that is potentially untrusted - e.g. a control in the browser) could call into the internals of a GACed assembly; it wants the public key to prevent this type of hack.

  2. This shouldn't break anything in production - even if the assembly cannot be found. This attribute is used during compile-time and not runtime.

What is the safest way?

If you are really worried about it breaking production code, remove the attribute during release builds:

#if (DEBUG || TEST)
[assembly: InternalsVisibleTo("MyTest, PublicKeyToken=XxxxxYysakf")] 
#endif

If you have a few projects that need the public key token (and you have a single key pair, which you should) you could also define a file such as AssemblyInfo.global.cs and add it as a linked file to all your projects:

class KeyTokens
{
   public const string Global = ", PublicKeyToken=XxxxxYysakf";
}

This simplifies things to (especially if you need to use the PublicKey which is really long):

#if (DEBUG || TEST)
[assembly: InternalsVisibleTo("MyTest" + KeyTokens.Global)] 
[assembly: InternalsVisibleTo("HisTest" + KeyTokens.Global)] 
[assembly: InternalsVisibleTo("TheirTest" + KeyTokens.Global)] 
#endif
Richard
  • 106,783
  • 21
  • 203
  • 265
Jonathan Dickinson
  • 9,050
  • 1
  • 37
  • 60
  • 1
    Unfortunately, the concatentation approach prevents IntelliSense from working in the "friend" VS project (https://connect.microsoft.com/VisualStudio/feedback/details/542121/intellisense-warns-red-sqiggle-incorrectly-for-internalsvisibleattribute-set-by-a-constant, https://connect.microsoft.com/VisualStudio/feedback/details/108537/internalsvisibleto-intellisense-signed-assemblies). Until/unless this is fixed, the concatenated constant approach is unlikely to find favour with most potential users. – Nicole Calinoiu Aug 25 '11 at 18:24
  • @Nicole - strange it works for me, possibly because we reference the assemblies by output file here and not project. – Jonathan Dickinson Aug 26 '11 at 07:55
  • It only affects project references. Unfortunately, the scenarios where friend assemblies tend to be most useful (semi-private APIs, exposing internals for testing) are also scenarios where folks tend to prefer to use in-solution project references. – Nicole Calinoiu Aug 26 '11 at 12:07