Geeks With Blogs
Jason Whitehorn MarshalByRefObject.net
UPDATE (12/17/2007): My blog has moved. This post is now located at: http://jason.whitehorn.ws/2007/11/09/The-Wonders-Of-InternalsVisibleTo.aspx




I do not know how I missed this, but just today I found out that you can expose an assembly's internal methods/properties/classes to a "friend" assembly. Normally internals are only accessible to members of the same assembly, and are often used to hide "plumbing" methods and utilities classes.

For many reasons you often want to separate your code into multiple assemblies, perhaps one for each application layer or some other logical boundary. A problem arises when two or more assemblies need access to each others internals. Prior to .NET 2.0 you had two choices, either expose these plumbing methods as public, or lump as much of your code into one assembly as was needed to keep the plumbing internal.

In comes .NET 2.0's InternalsVisibleTo attribute. This attribute is applied on the assembly level, and allows the assembly to give internal access to specific assemblies.

For example:

Say you have two assemblies, MyExample.DomainObjects & MyExample.ServiceLayer. In the DomainObjects assembly you have the following abstract class:


namespace MyExample.DomainObjects{
public abstract class DomainObject{
//.... other things....
public virtual DateTime LastModifiedDate{
get { ... }
internal set { ... }
}
}
}

In the above example you would like to have your service layer in a separate assembly from you domain objects. You would also like to have a LastModifiedDate property for each of your domain objects, but you would prefer if it was only settable by your service layer.

This is were the InternalsVisibleTo comes in handy. In the DomainObjects assembly you can added the InternalsVisbleTo attribute to give only the ServiceLayer assembly access to any and all internal items. For unsigned assemblies the attribute would look like:
[assembly: InternalsVisibleTo("MyExample.ServiceLayer")]

This is straight forward when the target assembly is unsigned, but gets a little more difficult when the target assembly is signed. For signed assemblies you will need the assembly's public key. This is not to be confused with the assembly's public key token, which is often what you see. To acquire the public key of a signed assembly you will need the "sn.exe" tool that ships with Visual Studio.

From the "Visual Studio Command Prompt":

sn -Tp c:\Users\jason\projects\MyExample\MyExample.ServiceLayer.dll

NOTE: the "sn" command takes a big "T" and a little "p" for the switch, and you will need to replace my example path with your own ;-)

Whats pops out of this handy little program is both the public key, and the public key token. The one we needs is the longer one, the public key. With this in hand we can now add the appropriate attribute to our DomainObjects assembly.

[assembly: InternalsVisibleTo("MyExample.ServiceLayer, PublicKey=0024000004809{key shortened for readability}30a09825a6999")]

NOTE: The public key is much longer than what is shown above. The above sample is intentionally incorrect for legibility. For this to work you will need to copy and paste the public key in its entirety.

With the public key added to the assembly name on the attribute our example ServiceLayer assembly can access the internals of the DomainObjects assembly.

Additionally, since the InternalsVisibleTo attribute references the friend assembly by its string name, no real dependency is created from our DomainObjects assembly to our ServiceLayer assembly. The DomainObjects assembly will continue to work with or without the ServiceLayer assembly present. Posted on Friday, November 9, 2007 8:53 PM .NET | Back to top

Comments have been closed on this topic.
Copyright © Jason Whitehorn | Powered by: GeeksWithBlogs.net | Join free