#Google Analytic Tracker

Pages

May 30, 2007

InternalsVisibleTo and Strong-Name signed assemblies

 

By now I am guessing only newbie like me would encounter this issue.  Today I was working on my project for my friend. Basically I am writing some kind of user name checking tool that can be call externally by a unmanaged program.  So, I figured that I need to expose my assembly as a COM object. I haven't test out my class yet, but hopefully it works.

Based on the article from my favorite CodeProject website:

Calling Managed .NET C# COM Objects from Unmanaged C++ Code

I need to accomplish 3 things

My class must be implement a specific interface

Both the interface and the class must have a GUID attribute to identify themselves

The assembly must be a strong-name type. (This is the part I am not sure why it has to be a strong-name type, but I am guessing it is because the writer decided to add the assembly to the GAC in his example from the article)

So, to ensure that I have a strong-name type, I followed the article procedure to create a snk (Strong Name Key) file.

Using Visual Studio 2005 Command Prompt,

> sn -k TestKeyPair.snk

The article suggested to do add "[assembly: AssemblyKeyFile("TestKeyPair.snk")]". After trying it, VS2005 warned me that I should added the snk file thought the Project->Properties->Signing tab, which I did

Now, here comes the tricky part, I have a UnitTests that test my internal method of my class.

SO, LET COMPILED

Error: Friends assembly must be strong-named signed (some error like that)

Ok, so it looks like I need to make sure that my UnitTests assembly need to be strong named too. So, I created another snk file call UnitTestsKey.snk, and added this file to my UnitTest project

Try again

   1:  
   2: [assembly: InternalsVisibleTo("UnitTests"]
   3:  
   4: // Compiling Error
   5: // Error 1 Friend assembly reference 'UnitTests' is invalid. 
   6: // Strong-name signed assemblies must specify a public key in 
   7: // their InternalsVisibleTo declarations.

What the heck is this "Public Key" I am missing? After hitting the F1 (for help, really I used F1 for help). Once again, MSDN helps doesn't explain much, especially for newbie like me. Let's GOOGLE it.

Ok, somehow I need to retrieve the public key from either the compiled DLL, or from the snk file.

This blog explains what I need to do, but it missing explain one important thing!

Which DLL's or SNK public key I need? My class, or my UnitTest class? It is important to know because I was confused on how this strong name type work.

After trials and errors, obvious it is the UnitTests's public key that I want.  The idea is that since my UnitTest is strong named and it is encrypted with this special snk file, to allow My Class shares its internal method, it needs to know the UnitTests assembly's public key.

Following the blog's explanation, I obtained the public key though the UnitTests.snk file. I can't get public key from the UnitTest assembly because it didn't compiled.

3rd Try

   1: [assembly: InternalsVisibleTo("UnitTests, PublicKeyToken=8c40a2440ba23747")]
   2:  
   3: // Compiling Error
   4: // Error 1 Friend assembly reference 'UnitTests, PublicKeyToken=8c40a2440ba23747' 
   5: // is invalid. Strong-name signed assemblies must specify a public key in their 
   6: // InternalsVisibleTo declarations.
   7:  

WTF? Let's Google it again.... hmmm... interesting some site is using PublicKeyToken, but some other doesn't, it uses PublicKey in the parameter string. Let use PublicKey

4th Try

   1: [assembly: InternalsVisibleTo("UnitTests, PublicKey=8c40a2440ba23747")]
   2:  
   3: // No compiling Error
   4: // but with Warning
   5: // Warning 1 Assembly reference 'UnitTests, PublicKey=8c40a2440ba23747' 
   6: // is invalid and cannot be resolved

Well, better, but when I compile my UnitTests project, it still failed. My UnitTests doesn't see the internal method of my Class....must be something do with the warning.

Finally, after reading more from an webpage (which unfortunately the webpage link is no longer working), it turns out that in Visual Studio 2005, you need to get the hex value for your public key.

5th Try

   1: [assembly: InternalsVisibleTo("LicenseKeyGeneratorExtendedTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000735a079d1bc7b8ea2b3e6706544e7396e4f3110b49c6529361d83ed66111c2fa4b38bbfb3d074d8ce76ed0a2813a2b9901ae0a88b79c85712e3ec4852fef4435426269f1009e2d79dc90644db171ec0566919f4945b06bce3603cc7af098d2774ec80b79bd182d4394bf75f775d0fecbf1b4ecb21a53aa6b0d9e218a1c223d0")]
   2:  
   3: // No Errors or Warnning

Finally, my solution compiled!

-------------------------------------

Update - Feb 11, 2009

If you still having trouble of making an assembly visible to another, check if you have the following line in your assembly.cs file and remove them:

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

Recently I tried to expose internal methods in a project to a unit test project.  My solution wouldn't compile, and after checking the assembly.cs in the project, I found these two line. Initially I thought it doesn't really do anything, but after I removed it, the solution compiled. I don't know why it was there in the beginning, but in any case, it works now.

Update – Mar 11, 2009

Some of the references were broken and they are now fixed.

Other References

Strong Names Explained

9 comments:

Anonymous said...

Thanks for sharing your steps to the solution, saved me a lot of time going through the same trouble.

iamvalentin said...

Hi,
There is easier way to get the public key.
Just run the reflector and switch to IL mode.
In C# mode it shows the PublicKeyToken, but in IL mode it shows the whole Public Key.
Hope this is helpful for you.

Valentin.

oggy said...

Valentin, can you explain what reflector and switching to IL mode are? How you can do it?

Dicky said...

Hi oggy,

Reflector is a decompiler for .NET program.
http://www.red-gate.com/products/reflector/

You can load a dll into .NET Reflector and look at the IL (Intermediate Language) code. The PublicKeyToken probably displays some where.

Anonymous said...

A link between 4th try and 5th try is broken :(

Scott Thornock said...

5th try works for me, I had the same problem in VS.NET 2008.
One important thing to note is that you can get hex value of public key by using sn.exe -tp key.pub

Seth said...

Thanks for the post!

Anonymous said...

You should also ensure that [assembly: AssemblyDelaySign(false)] is not present in the AssemblyInfo.cs.

Anonymous said...

Very nice and informative article that beautifully elaborate the basics of Strong Name in Assembly. Check out this link too its also explained very well about strong name in assembly.
Strong Name in Assembly