Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Thursday, July 16, 2009

InternalsVisibleTo and Chasing Down Public Keys

Sometimes, just getting assemblies to cooperate the way you want them to is a real pain in the neck.

Today, I wanted to make one assembly (which we’ll call Foo) to be able to access the internal (Friend for all us VB geeks) members of another assembly (which we’ll call Bar). Now, the documented way to achieve this is by adding the InternalsVisibleTo attribute to your project. The code sample on MSDN looks like this:

[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")]

For a Visual Basic application, that statement goes into the AssemblyInfo.vb file, and looks like this:

<Assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")>

No big deal. It’s not rocket science. You just need a strong name. To generate a strong name, you fire up the Visual Studio Command Prompt, and execute the Strong Name tool (sn.exe) and execute it as follows:


C:\Program Files\Microsoft Visual Studio 9.0\VC>sn.exe -k bar.snk

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Key pair written to bar.snk

As you can see, this creates a .SNK file, which contains a public and a private key. However, its contents are not human readable. Further, the InternalsVisibleTo attribute requires that you provide the public key in the constructor. (Don’t even think about trying it without it.)


Here’s where things get tricky: The code samples on MSDN do not provide a public key to the constructor; they provide a public key token. There’s a huge difference between the two, and it’s very misleading. A strong name token is much shorter than a public key; the former is only about 16 characters long, the other well in excess of 140 characters. If you rely on the code sample from MSDN to get you where you want to be, you’ll be pulling your hair out in no time.


But how do you get the public key token?


You can retrieve the public key token as follows:


sn –p foo.snk barpublic.snk


This creates a new file that contains only the public key. It removes the private key information from the file.


sn –tp > barkey.txt


This creates a text file that contains the full dump of the key information, including the public key. We redirect it to a text file so that you can open it in the editor of your choice (because you’ll have to do some cleanup to get the key onto one line). You’ll want to select the public key and paste it into the PublicKey portion of the constructor for the InternalsVisible attribute.


So here’s everything we did at the command prompt:


C:\Program Files\Microsoft Visual Studio 9.0\VC>sn -k bar.snk

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Key pair written to bar.snk

C:\Program Files\Microsoft Visual Studio 9.0\VC>sn -p bar.snk barpublic.snk

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Public key written to barpublic.snk

C:\Program Files\Microsoft Visual Studio 9.0\VC>sn -tp barpublic.snk > bar.txt

C:\Program Files\Microsoft Visual Studio 9.0\VC>

And here’s the contents of our text file:


Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Public key is
0024000004800000940000000602000000240000525341310004000001000100e13cb392af5437279736fc3c33fe237242d0f6301fafb01c5cbc719d84102c2d8b30a148600997ed53d99624b5d0eab37fd6b24cca3ce7f7b62ae99f961e148d5421576bade0ac8ab1187a3eee318ca20026ffe9b56b8a63156f817cef49998633867ae547684e8e59c0fe0b68ab29dffa749340dc6cfdd18071f1b69c6772ac

Public key token is db218359dd8997df

So, when we finally add that attribute to our AssemblyInfo.vb file, it looks like this:


<Assembly:InternalsVisibleTo("Bar, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e13cb392af5437279736fc3c33fe237242d0f6301fafb01c5cbc719d84102c2d8b30a148600997ed53d99624b5d0eab37fd6b24cca3ce7f7b62ae99f961e148d5421576bade0ac8ab1187a3eee318ca20026ffe9b56b8a63156f817cef49998633867ae547684e8e59c0fe0b68ab29dffa749340dc6cfdd18071f1b69c6772ac")>

Once this stuff is in place, Bar should be able to access any members in Foo that are marked internal/Friend. It should be smooth sailing from there.

Good luck!


Friday, January 25, 2008

Is VB.NET vs. C# Really Just Syntactic Sugar?

I recently read somewhere, as I have read before, that there aren’t any really compelling differences between C# and VB.NET. As has often been repeated, the differences all really boil down to “syntactic sugar.” C# is nice and terse, deriving its tight syntax from C and C++, while Visual Basic uses verbose language in an attempt to achieve greater clarity. Once the compilers get the code, though, it’s all supposed to be the same MSIL that gets generated, because you’re targeting the same .NET Framework.

So, it’s been asked, why would you choose one over the other?

That’s a fairly intriguing question. I’ve been working with VB and VB.NET for a really long time, and I’ve also had the opportunity to work with C, C++, Java, and C#. I like them all. I’d have to say that you can’t really beat VB for getting something up and running really damn fast.

But I’ve started to get this really deep-seated gnawing in the pit of my gut about what kinds of bad habits I’ve picked up over the years. VB has a reputation for doing things “automagically” to ease your life for you. Implicit type casting, dynamic variable allocation, case insensitivity, and a host of other little time-savers are designed to shield you from the nitty-gritty details of brain-cramping compiler complexities.

As a thought experiment, I took a large code base here at the office and ran it through C-Sharpener, a utility that converts VB.NET code to C#. Now, as a rule, I figure I write fairly safe code. I try to avoid reliance on the Microsoft.VisualBasic namespace, and use the Framework code instead. I always use Option Strict On (except for one particular class that used Reflection), and always explicitly define my variables. I’m a huge fan of type safety, so that wasn’t a concern to me.

What I didn’t expect to find were the things that C# complained about that I’d been doing and it told me, in no uncertain terms, were foolishness.

For instance, in Visual Basic, this is perfectly acceptable:

Imports System.Diagnostics
Dim log As New EventLog("Application", Environment.MachineName, "MyApp")
log.WriteEntry("MyApp", "Message Text", EventLogEntryType.Information)

(Ignore the crappy code. Just focus on the point I’m making.)

This will get you a wrist-slap from the C# compiler. Why? Because that particular overload of the WriteEntry method is static. You can’t invoke static methods from an instance variable in C#. The compiler flatly refuses to let you do so. Visual Basic, on the other hand, thinks that’s just fine and dandy; it resolves the issue on the fly for you.

Does that sound like syntactic sugar to you?

In Visual Basic, this is just fine and dandy:

If CInt(txtQuantity.Text) Then
   ' Do something spectactular
End If

Visual Basic helpfully converts the result of CInt to a Boolean to help evaluate the If...Then statement. If it’s nonzero, you get True and something spectacular happens.  In C#, you get a lovely compiler error about not being able to cast an int to a bool. Why? Because an int isn’t a bool, stupid!

"Yeah, yeah. So what? But I always want to do that." Good. So prove it. Explicitly cast, and for Pete’s sake work with the right data type. It shows me that you’ve thought about that when you wrote it. Visual Basic doesn’t force you to make your intent clear. C# does.

if ( 0 != int.Parse(txtQuantity.Text) ) {
  // do something spectactular
}

Again, does that sound like syntactic sugar to you? Remember, intent != syntax.

In Visual Basic, you can do this for days and the compiler will pat you on the back while you do it:

Public Function FooBar() As Integer
   Dim result As Integer
   Return
result  
   ' Do some more real work--that's unreachable
   Return result
End Function

Does the compiler care? Nope. Not a peep. C#, on the other hand, gives you this nifty warning: “Unreachable code detected.” Then it gives you the file name and line number where it’s at. It’s like your best friend saying, “Hey man, you really don’t want to do that.”

There’s no way that’s just syntactic sugar.

So here I am, looking at this project that I’ve converted, and I’m both pleased and shocked. Pleased because the number of conversion issues and errors is relatively minor. Shocked because I found myself doing things that I didn’t think I was doing. They just creeped up on me and seeped into me like bad habits all to often do.

I’ve been wanting to make the switch from VB to C# for some time now. Doing this conversion turned out to be a good thing for one very compelling reason: it opened my eyes to the mistakes I’ve been making, the bad habits I’ve adopted. I’m sold on C# now as my full time language. I’ll miss the speed of development of VB, but if slowing down means I write higher quality code that contains fewer bugs that have to be squashed later at higher cost, isn’t that worth it?

In the end, the point of this post is this: C# and VB are not simply different by the syntactic sugar that distinguishes them. The power of their compilers and the strictness of their adherence to OO principles also separates them. I’d wager a guess that it’s C#’s strictness that makes its compiler so much more powerful than VB’s. I certainly don’t see messages about unreachable code, expressions never being of the provided type, static method invocation, and so forth from VB. 

So please. Don’t over-simplify the issue. View the languages for what they are, and use the one that’s appropriate for what you’re doing, and how you work. For me, I’m making the switch. It makes sense for me. It won’t for everyone. But I am, by definition, an obsessive-compulsive control freak. I demand to know what I’m doing wrong and then I want to ruthlessly correct it. And I can’t reasonably ask for a harsher taskmaster at this point than an unforgiving, absolutist object oriented compiler.