Introduction:
This tutorial describes the major advantages of using assemblies, including the packaging and versioning of your .NET components. You’ll also see how to create single-file and multifile assemblies by using the Assembly Generation tool (al.exe), how to create shared assemblies by using the Strong Name tool (sn.exe), how to browse the global assembly cache by using the Assembly Cache Viewer shell extension (shfusion.dll), and how to manipulate the assembly cache with the Global Assembly Cache tool (gacutil.exe). Finally, we’ll go through several demos and see what the fuss is about versioning and how assemblies and .NET versioning policies help you to avoid DLL hell.
Main:
Basic Definition for Assembly:-Assemblies as physical files that consist of one or more portable executable (PE) files generated by a .NET compiler.
Complete Definition: an assembly is the packaging of a manifest, one or more modules, and, optionally, one or more resources. Using assemblies allows you to semantically group functional units into a single file for purposes of deployment, versioning, and maintenance.
Brief Technical Explanation:-All PE files that use the .NET runtime consist of an assembly or a group of assemblies. When you compile an application by using the C# compiler, you’re actually creating an assembly. You might not realize that fact unless you’re specifically attempting to place multiple modules in a single assembly or taking advantage of some assembly-specific feature such as versioning. However, it’s important to realize that any time you build an EXE or a DLL (using the /t:library switch), you’re creating an assembly with a manifest that describes the assembly to the .NET runtime. In addition, you can create a module (using the /t:module switch) that is really a DLL (with an extension of .netmodule) without a manifest. In other words, although logically it’s still a DLL, it does not belong to an assembly and must be added to an assembly either by using the /addmodule switch when compiling an application or by using the Assembly Generation tool.
An assembly’s manifest can be stored in different ways. If you were to compile a stand-alone application or DLL, the manifest would be incorporated into the resulting PE. This is known as a single-file assembly. A multifile assembly can also be generated, with the manifest existing as either a stand-alone entity within the assembly or as an attachment to one of the modules within the assembly.
The definition of an assembly also largely depends on how you’re using it. From a client’s perspective, an assembly is a named and versioned collection of modules, exported types, and, optionally, resources. From the assembly creator’s viewpoint, an assembly is a means of packaging related modules, types, and resources and exporting only what should be used by a client. Having said that, it’s the manifest that provides the level of indirection between the implementation details of the assembly and what the client is meant to use. Here’s a breakdown of the information that gets stored in an assembly’s manifest: -
* Assembly name The textual name of the assembly.
* Versioning information This string contains four distinct parts that make up a version number. They include a major and minor version number as well as a revision and build number.
* An (optional) shared name and signed assembly hash This information pertains to the deployment of assemblies and is covered in “Assembly Deployment” later.
* Files This list includes all files that exist in the assembly.
* Referenced assemblies This is a list of all external assemblies that are directly referenced from the manifest’s assembly.
* Types This is the list of all types in the assembly with a mapping to the module containing the type.
* Security permissions This is a list of security permissions that are explicitly refused by the assembly.
* Custom attributes As with types, custom attributes are stored in the assembly’s manifest for quicker access during reflection.
* Product information This information includes Company, Trademark, Product, and Copyright values.
Assemblies afford the developer numerous benefits, including packaging, deployment, and versioning.One advantage of the ability to package multiple modules in a single physical file is performance improvement. When you create an application and deploy it using a multifile assembly, the .NET runtime needs to load only the required modules. This has the effect of reducing the working set of the application.
The smallest unit of deployment in .NET is the assembly. As I mentioned previously, you can create a .netmodule with the /t:module switch, but you must include that module in an assembly if you wish to deploy it. In addition, although it’s tempting to say that assemblies are a means of application deployment, this is not technically true. It’s more accurate to view assemblies in .NET as a form of class deployment (much like a DLL in Win32), in which a single application can be made up of many assemblies.
Because assemblies are self-describing, the easiest method of deploying them is copying the assembly to the desired destination folder. Then when you attempt to run an application contained in the assembly, the manifest will instruct the .NET runtime as to the modules that are contained in the assembly. In addition, the assembly also contains references to any external assemblies that are needed by the application.
The most common means of deployment is though private assemblies-that is, assemblies that are copied to a folder and that are not shared. How do you specify a private assembly? This is the default and occurs automatically unless you explicitly make the assembly a shared assembly.
Another great advantage to using assemblies is built-in versioning-specifically, the end of “DLL hell.” “DLL hell” refers to the situation in which one application overwrites a DLL needed by another application, usually with an earlier version of the same DLL, breaking the first application. Although the Win32 resource file format does allow for a versioning resource type, the operating system doesn’t enforce any versioning rules so that dependant applications will continue to function. This is solely the responsibility of application programmers.
As a means of addressing this issue, the manifest includes versioning information for the assembly as well as a list of all referenced assemblies and the versioning information for those assemblies. Because of this architecture, the .NET runtime can ensure that versioning policies are upheld and applications will continue to function even when newer, incompatible versions of shared DLLs are installed on the system.
If you create a DLL with the /t:library switch, you won’t be able to add it to another assembly. This is because the compiler automatically generated a manifest for the DLL, and therefore the DLL itself is an assembly. To see this in action, look at the following example. We have a DLL (Module1Server.cs) that has a dummy type called Module1Server.
// Module1Server.cs // build with the following command line switches // csc /t:library Module1Server.cs public class Module1Server { } |
This DLL is then referenced by the client code (Module1Client.cs): -
// Module1ClientApp.cs // build with the following command line switches // csc Module1ClientApp.cs /r:Module1Server.dll using System; using System.Diagnostics; using System.Reflection; class Module1ClientApp { public static void Main() { Assembly DLLAssembly = Assembly.GetAssembly(typeof(Module1Server)); Console.WriteLine("Module1Server.dll Assembly Information"); Console.WriteLine("\t" + DLLAssembly); Process p = Process.GetCurrentProcess(); string AssemblyName = p.ProcessName + ".exe"; Assembly ThisAssembly = Assembly.LoadFrom(AssemblyName); Console.WriteLine("Module1Client.exe Assembly Information"); Console.WriteLine("\t" + ThisAssembly); } } |
Now let’s say you built these two modules by using these switches: -
csc /t:library Module1Server.cs
csc Module1ClientApp.cs /r:Module1Server.dll
Running the code at this point results in the following output and proves that both the EXE and the DLL exist in their own distinct assemblies: -
Module1Server.dll Assembly Information
Module1Server, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Module1Client.dll Assembly Information
Module1Client, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
In fact, if you were to change the access modifier of the Module1Server class from public to internal, the client code wouldn’t compile because by definition the internal access modifier specifies that the type being modified is accessible only to other code in the same assembly.
You can place both of the modules in our example into the same assembly in two ways. The first way is to change the switches used with the compiler. Here’s an example: -
// Module2Server.cs // build with the following command line switches // csc /t:module Module2Server.cs internal class Module2Server { } |
Notice that we can now use the internal access modifier so that the class is only accessible to code within the assembly.
// Module2ClientApp.cs // build with the following command line switches // csc /addmodule:Module2Server.netmodule Module2ClientApp.cs using System; using System.Diagnostics; using System.Reflection; class Module2ClientApp { public static void Main() { Assembly DLLAssembly = Assembly.GetAssembly(typeof(Module2Server)); Console.WriteLine("Module1Server.dll Assembly Information"); Console.WriteLine("\t" + DLLAssembly); Process p = Process.GetCurrentProcess(); string AssemblyName = p.ProcessName + ".exe"; Assembly ThisAssembly = Assembly.LoadFrom(AssemblyName); Console.WriteLine("Module1Client.dll Assembly Information"); Console.WriteLine("\t" + ThisAssembly); } } |
Notice how Module2Server.cs and Module2Client.exe are built: -
csc /t:module Module2Server.cs
csc /addmodule:Module2Server.netmodule Module2Client.cs
First you must remove the /r switch because that switch is used only to reference assemblies and now both modules will reside in the same assembly. Then you must insert the /addmodule switch, which is used to tell the compiler which modules to add to the assembly that’s being created.
Building and running the application now yields these results: -
Module1Server.dll Assembly Information
Module2Client, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Module1Client.dll Assembly Information
Module2Client, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Another way to create an assembly is with the Assembly Generation tool. This tool will take as its input one or more files that are either .NET modules (containing MSIL) or resource files and image files. The output is a file with an assembly manifest. For example, you would use the Assembly Generation tool if you had several DLLs and you wanted to distribute and version them as a single unit. Assuming that your DLLs were named A.DLL, B.DLL and C.DLL, you would use the al.exe application to create the composite assembly as follows: -
al /out:COMPOSITE.DLL A.DLL B.DLL C.DLL
Sharing assemblies is done when an assembly is to be used with multiple applications and versioning is important. (We’ll get to versioning in the next section.) To share an assembly, you must create a shared name (also known as a strong name) for the assembly by using the Strong Name tool that accompanies the .NET SDK. The four main four benefits derived from using strong names are the following: -
* It’s the mechanism in .NET for generating a globally unique name.
* Because the generated key pair (explained shortly) includes a signature, you can tell whether it’s been tampered with after its original creation.
* Strong names guarantee that a third party can’t release a subsequent version of an assembly you built. Once again, this is because of signatures-the third party won’t have your private key.
* When .NET loads an assembly, the runtime can verify that the assembly came from the publisher that the caller is expecting.
The first step to creating a strong name is to use the Strong Name tool to create a key file for the assembly. This is done by specifying the -k switch with the name of the output file that will contain the key. Here we’ll just make something up-InsideCSharp.key-and create the file as follows: -
sn -k InsideCSharp.key
Upon running this, you should get a confirmation message like the following: -
Key pair written to InsideCSharp.key
Now add the assembly:AssemblyKeyFile attribute to the source file. Here, I’ve created another simple set of files to illustrate how this is done: -
// Module3Server.cs // build with the following command line switches // csc /t:module Module3Server.cs internal class Module3Server { } // Module3ClientApp.cs // build with the following command line switches // csc /addmodule:Module3Server.netmodule Module3ClientApp.cs using System; using System.Diagnostics; using System.Reflection; [assembly:AssemblyKeyFile("InsideCSharp.key")] class Module3ClientApp { public static void Main() { Assembly DLLAssembly = Assembly.GetAssembly(typeof(Module3Server)); Console.WriteLine("Module1Server.dll Assembly Information"); Console.WriteLine("\t" + DLLAssembly); Process p = Process.GetCurrentProcess(); string AssemblyName = p.ProcessName + ".exe"; Assembly ThisAssembly = Assembly.LoadFrom(AssemblyName); Console.WriteLine("Module1Client.dll Assembly Information"); Console.WriteLine("\t" + ThisAssembly); } } |
As you can see, the assembly:AssemblyKeyFile attribute’s constructor takes the name of the key file that was generated with the Strong Name utility and is the means by which you specify a key pair to be used to give your assembly a strong name. One more important point to understand is that this attribute is an assembly-level attribute. Therefore, technically, it can be placed in any file in the assembly and isn’t attached to a specific class. However, it’s customary to place this attribute just below the using statements and before any class definitions.
Now when you run the application, take note of the PublicKeyToken value of the assembly. This value was null in the previous two examples because those assemblies were considered to be private assemblies. However, now the assembly has been defined as a shared assembly, and so the assembly has an associated public key token.
Module3Server.dll Assembly Information
Module3Client, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=6ed7cef0c0065911
Module3Client.dll Assembly Information
Module3Client, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=6ed7cef0c0065911
-According to the Assembly object that we instantiated for this demo assembly, it is shared. However, how do we know which assemblies in our .NET system are shared? The answer is the global assembly cache. In the next section, I’ll cover this part of .NET and explain the role it plays in shared assemblies. -
Conclusion:
Hope this helps to understand .NET Assemblies,
Happy Coding.
References:
msdn.microsoft.com
I’m so glad to have found your web page. My pal mentioned it to me before, yet never got around to checking it out until now. I must express, I’m floored. I really enjoyed reading through your posts and will absolutely be back to get more.
Sounds so tricky but i will try it.
I have to compile the Form1.cs file along with the third party dependencies using the command propmp “CSC”
Any help
Hi Prami,just host the dll into bin using gacutil ( gacutil -i Third party dll bin path),and just build it thatsit,
This is one technology that I would love to be able to use for myself. It’s definitely a cut above the rest and I can’t wait until my provider has it. Your insight was what I needed. Thanks
beneficialinformation shared..Iam very happyto read this article..thanks for giving us nice info.Fantastic walk-through.
Thanks for the great insight on that, never really thought about it. bookmarked your site! pepsibookcat
I wanted to say that it’s nice to know that someone else also mentioned this as I had trouble finding the same info elsewhere. This was the first place that told me the answer. Thanks.
Thanks For This Post, was added to my bookmarks.
You certainly deserve a round of applause for your post and more specifically, your blog in general. Very high quality material
Hey, I’m having a problem viewing your site in my browser. Could you please check this. My browser is Opera 7 btw.
I truly see that your published content is rather great as it comes with an assorted range of accurate info. Anyway, was wondering whether you would love to exchange web links with my website, as I am looking forward to build web links to further amplify and gain better web exposure for my web site. I do not mind you locating my web links at the homepage, just getting this links on this respective page is more than adequate. Furthermore, would you please contact me at my web portal if you are keen in the link exchange, I would really appreciate that. Best wishes from me and I hope to hear from you shortly!
I just book marked your blog on Digg and StumbleUpon.I enjoy reading your commentaries.
Thanks for the sharing really usefull. I would like to bookmark this site.
Hey, I’m having a problem viewing your site in my browser. Could you please check this. My browser is Opera 7 btw.
i know this is not exactly on topic, but i have a blog using the blogengine platform as well and i’m having issues with my comments displaying. is there a setting i am forgetting? maybe you could help me out? thank you.
Hi webmaster, commenters and everybody else !!! The blog was absolutely fantastic! Lots of great information and inspiration, both of which we all need!b Keep ‘em coming… you all do such a great job at such Concepts… can’t tell you how much I, for one appreciate all you do!
I hate to sound like a nitpick, but your grammar is just…deplorable. I want to be interested in this, I really do. But it seems you spent so much time on the design (which, I will say, is amazing) that you forgot that people actually have to read your blog. Clean this up…PLEASE. It could be so much bigger if you just did some work.
I thought it was going to be some boring old post, but it really compensated for my time. I will post a link to this page on my blog. I am sure my visitors will find that very useful.
I wanted to say that it’s nice to know that someone else also mentioned this as I had trouble finding the same info elsewhere. This was the first place that told me the answer. Thanks.
Easily, the post is actually the greatest on this deserving topic. I agree with your conclusions and will thirstily look forward to your coming updates. . . . .
Hello,After reading you site, Your site is very useful for me .I bookmarked your site!
I feel you are too good to write Genius!Thanks for posting, maybe we can see more on this.
Alot of the time i see pages with silly comments and thought wouldn’t it be nice to be one.. Nice blog found you via google. Will check back. See what other jems you post.
Stumbled into this site by chance but I’m sure glad I clicked on that link. You definitely answered all the questions I’ve been dying to answer for some time now. Will definitely come back for more of this. Thank you so much
Valuable info. Lucky me I found your site by accident, I bookmarked it.
this post is very usefull thx!
Great information! I’ve been looking for something like this for a while now. Thanks!
What a cool and easy explanation…!
I was feeling what the heck is all about Assemblies.
Now i am comfortable with Assemblies.
Hats off….
Of course, what a perfect internet site and informative posts, I will add backlink – bookmark this webpage? Regards, Reader.
Good posting. I had been checking this website and that i’m impressed! Extremely helpful info particularly the previous portion
I care for such info a lot. I was looking for this particular information for a very long time. Thanks and all the best ..