How can I make InternalsVisibleTo attribute work by signing a public token key safely?

pencilCake picture pencilCake · Aug 25, 2011 · Viewed 16.6k times · Source

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?

Answer

Jonathan Dickinson picture Jonathan Dickinson · Aug 25, 2011

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