Ok, this may be old hat and I'm the last on the planet to discover this, but I'm pretty excited!
Since my induction into the .NET world (which was graceful and without incident) I have had a beef with one aspect of it - Type visibility. If I create a Class Library (aka DLL) and create public types, I really can't designate who can use those classes. - they're open to the world. Ok, ok, there are ways to enforce this such as by applying the StrongNameIdentityPermissionAttribute to the type.
The StrongNameIdentityPermissionAttribute (SNIPA, affectionately) is a pretty slick attribute that you can apply to a variety of things: assemblies, classes, structs, constructors, and methods. This attribute effectively marks the item as useable only by a client with a given strong name.
Demonstration of how to use the StrongNameIdentityPermissionAttribute:
1. Create your strong name (e.g: sn -k KeyFile.snk) for your client application.
2. Sign your client assembly with the strong name (e.g: [assembly: AssemblyKeyFile(@”..\..\KeyFile.snk”)])
3. Set a reference to the DLL (class library) in the client (note, it will have to also have a strong name so follow steps 1 and 2 for the DLL, possibly reusing the .snk file if you want)
4. Identify the class / method / etc that you only want to be callable by the client application. This is the item to which you will apply the SNIPA. A simple way to identify the strong name for the calling client is to retrieve it's public key. This is done against the compiled client .exe/.dll (e.g: secutil -hex -s ClientApp.exe or sn -Tp ClientApp.exe) [Updated 02/23/2005 - Didn't want to forget the sn.exe utility]. This will output the public key in hex format. Copy and paste it into your code:
using System.Security.Permissions;
namespace ClassLibrary1 {
[StrongNameIdentityPermission(SecurityAction.Demand, PublicKey=”......”)]
public sealed class Class1 { ... }
}
There really isn't much more to it than that. Only clients signed with the specified strong name will be able to create instances of the designated type and call its methods. Pretty slick stuff.
There are a few caveats and restrictions, however, with using the SNIPA.
1. Firstly, SNIPA applies only to one type. That is, if you have multiple types that you want to share with a designated strong-name-signed application, you must mark each and every type individually, otherwise they're public to the world.
2. Secondly, the items flagged with the SNIPA must be public. They cannot be internal types.
3. You can designate only one SNIPA per element; you cannot identify two different strong names. You have one friend and that's it.
Today, I made a great discovery that I thought worth sharing, and this brings me back to the original purpose of the post in the first place. In the Whidbey timeframe you will be able to designate friend assemblies with a fantastic attribute called InternalsVisibleToAttribute. This attribute can be applied to your assembly thus: [assembly: InternalsVisibleTo(”...”)]. One nice and enabling characteristic of this attribute is you can apply it multiple times to your assembly to designate multiple 'friends' unlike the SNIPA with which you can only designate a single category of friends: those with a given strong name.
The coolness behind this is you can create types that are internal to your application, and now internal can actually extend beyond the scope of your DLL and into your 'family of products' without exposing unnecessary objects and types to the public world. I am SO excited for this feature as I was wanting to take advantage of such functionality since the beginning.
Way to go .NET team!