Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use "InternalsVisibleTo" attribute with Strongly named assembly?

I am using the "InternalsVisibleTo" attribute with an assembly to expose the internal methods/classes to my unit test project.

I now need to install that assembly into the GAC, so I need to give it a strong name. When I try doing that, I get the following error in Visual Studio.

Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations

A bit of Googling brought me to the article below:

https://msdn.microsoft.com/en-us/library/bb763089.aspx

This article states:

"Determine the public key for the strong-named friend assembly."

This article does not say how to determine the public key. Where do I find the public key for the assembly? Also, once I have the public key, would this be the correct way to declare the attribute?

[assembly: InternalsVisibleTo("Namespace.Assembly.Example.Name, PublicKey=ThePublicKey")]
like image 271
Dave Avatar asked Jun 19 '15 16:06

Dave


People also ask

What's the usage of InternalsVisibleTo attribute?

From the documentation, the assembly-level InternalsVisibleTo attribute: Specifies that all nonpublic types in an assembly are visible to another assembly. This attribute was introduced in C# 2.0, and allows you to specify other assemblies that can see all types and members marked “internal”.

Where do you put InternalsVisibleTo?

Assembly-level attributes can appear in any code file; however, by convention they are placed in the AssemblyInfo file. This aids discoverability, as this is where people (or tools) will commonly look when investigating issues. I have been using InternalsVisibleTo for many years and placing it in the AssemblyInfo file.

What is strongly named assembly in net?

A strong named assembly is generated by using the private key that corresponds to the public key distributed with the assembly, and the assembly itself. The assembly includes the assembly manifest, which contains the names and hashes of all the files that make up the assembly.

How do I find the public key of signed assembly?

The public key token is a unique 16-character key that is given to the assembly when it is built and signed in Microsoft Visual Studio. To determine the public token key, you can run the Strong Name tool (sn.exe) on the assembly. The sn.exe is available with the Microsoft . NET Framework SDK.


3 Answers


UPDATE May 2019 : It works perfectly with Visual Studio 2019.


UPDATE May 2022 : as mentioned by @Igor Meszaros It also works with Visual Studio 2022.


To anyone that is using Visual Studio 2017, there is the latest method :

From our beloved IDE, go to "Tools > External Tools..." and "Add" a new tool with those settings :

  • Title : Get PublicKey
  • Command : "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\sn.exe" (/!\ choose the NETFX tool version that match your assembly NETFX version, here it's 4.6.2)
  • Arguments : -Tp $(TargetPath)
  • Check the "Use Output window" checkbox

Apply/OK those changes.

In the "Solution explorer" click on your project assembly name, and then head to "Tools > Get PublicKey". The Output window should display the (quite long) Public Key, along with the Public Token Key.

Finally, in the project that holds the internal class (i.e. the tested project) you want to expose, open the "AssemblyInfo.cs" file and add the line :

[assembly: InternalsVisibleTo("MyCompany.SolutionName.ProjectName, PublicKey=Paste your public key here")]

/!\ You have to remove the line breaks from your public key.

It worked perfectly for me, so hopefully it'll do the trick for you as well !

like image 134
Invvard Avatar answered Oct 04 '22 16:10

Invvard


To use InternalsVisibleTo with strongly signed assembly your "friends" assemblies must be strongly signed too. Public token of the test assembly need to be specified as part of InternalsVisibleTo value.

Note that the attribute is not used for actual validation of assembly at compile time - it only specifies that run-time checks (and compile-time checks for friend's assembly) should validate that identity. So if you just need to compile your main assembly you can specify any public key token (i.e. one from Microsoft's assemblies as found on all assembly references in your Web.Config for example).

Generally since you'll be signing assemblies you'd know the public key. I.e. if you have snk file than sn -t youSnk.snk would show the public key. Or you can follow steps in Getting Public Key Token of Assembly Within Visual Studio to configure your VS to show public token for any assembly which uses sn -Tp {path to assembly} to get public key from the assembly. (If document is gone steps are copied to the other answer to this question)

like image 22
Alexei Levenkov Avatar answered Oct 04 '22 17:10

Alexei Levenkov


I use an old good method from classic fiction movies: "hacker always guesses password in a second attempt". It's simple technique and it doesn't require any tools besides what you already have - some unit test framework. And yes, assembly under test must be signed, as mentioned here multiple times.

Copy and paste this class below to your test DLL. It's xUnit test but the same approach works well with any unit test framework.

public class FindOutAssemblyPublicKey
{
    const string AssemblyPK = "Swordfish";

    /// <summary>
    /// Fake test to find out a correct PublicKey in InternalsVisibleTo for assembly under test.
    /// </summary>
    [Fact]
    public void AssemblyPublicKeyIsAsExpected()
    {
        byte[] publicKey = GetType().Assembly.GetName().GetPublicKey();
        var sb = new StringBuilder();
        foreach (byte @byte in publicKey)
            sb.AppendFormat("{0:x2}", @byte);

        // Set breakpoint here to find out what's in sb
        Assert.Equal(AssemblyPK, sb.ToString());
    }
}

The idea here is quite simple: test fails at first run but reveals a correct public key of the test assembly. To double check replace "Swordfish" with what you've got as actual value, run test second time to make sure it's green and here you are.

like image 41
Remigijus Pankevičius Avatar answered Oct 04 '22 16:10

Remigijus Pankevičius