The concept of components has been around for many years, the idea is to divide your code into smaller manageable units, which exhibits some known behavior, and then integrate your application with the help of these components rather than make one huge monolithic block of code. The idea was to implement code reuse and version control of the code.
With .NET, Microsoft has tried to retain the benefits of COM while addressing the accompanying problems with the same. These complexities and problems have been addressed by returning to the concept of Class in , for e.g. C++ .
So a simple C# component can be viewed as a C# class, but with the benefit of being easy to call a method of that class across a DLL and language boundaries. So if you want to create a .NET component, you can just write a .NET class and adhere to some guidelines laid down by Microsoft. They can be summarized as follows.
- CLS Compliant: Microsoft has laid down a common language specification, which is a set of facilities that any 3rd party compiler that targets .NET must support. Hence .NET components must use only features in their methods and properties that are defined in the CLS. This ensures that any compiler, which is able to compile a particular piece of code, will make full use of the component.
- Public Access: The classes inside your component should be marked as Public rather than as Private, which allows the outside world to interact with it. If it is marked private, nothing outside the component can access these classes, which, of course restricts its usefulness as a component.
- System.ComponentModel.Component: The classes should inherit from the System.Component.ComponentModel or implement the IComponent Interface. This adds a few methods to your classes, which enable code sharing.
- Naming Conventions: Microsoft lays down the guidelines for the naming your classes, methods and properties. These full guidelines can be found in the MSDN documentation for .NET.
. NET Assemblies
A .NET component is now known as an Assembly. An assembly is an atomic unit and is self-describing i.e. it doesn't just contain the code but also it's meta data. This meta data is contained in a data structure called Manifests. With a DLL, the manifest is incorporated with the code itself, this is known as a single file assembly. Multi file assembly can also be created where the manifest exists as a stand-alone entity within the assembly or as one of the modules in the assembly.
The Manifest contains the following:
- The identity of the assembly which consists of it's name, version and culture.
- A Shared Name if it is a shared assembly (explained later).
- Names of all the files in the assembly.
- A encrypted hash of all the files in the assembly. This hash is used to detect all the changes that occur with the files in the assembly.
- Details of all the classes, methods and properties , i.e whether they are public, private, protected etc.
- Names and hashes of all the assemblies that the current assembly references.
- Security Details
The manifest serves the same purpose as the type library does with COM. The difference is that the manifest contains more information than the type library and it is directly packaged with the code which allows them to be in sync with each other at all times.
Assemblies can be of two types :
By default , when an assembly is created, it is a Private Assembly i.e the assembly is intended only for one application. The files of that assembly must be placed in the same folder as the application or in a sub folder. No other application will be able to make a call to this assembly. The advantage of having an private assembly is that , it makes naming the assembly very easy, since the developer need not worry about name clashes with other assemblies. As long as the assembly has a unique name within the concerned application, there won't be any problems. If a private assembly is to be accessed by more than one application, then the files of the assembly has to be placed separately within the folders of each application which needs to access the assembly.
If the assembly is to be made into a Shared Assembly, then the naming conventions are very strict since it has to be unique across the entire system. The naming conventions should also take care of newer versions of the component being shipped. These is accomplished by giving the assembly a Shared Name. Then the assembly is placed in the global assembly cache which is a folder in the file system reserved for shared assemblies. There are a lot of utilities available which can convert private assemblies into shared assemblies. It can't be done at compile time.
Advantages of Assemblies
With earlier component architectures like COM , the components had to be registered in the system registry which gave the benefit that it was easily to identify the components on a particular system. But with time, several disadvantages have been seen with this approach. Firstly it made the task of installing software very complex. Then , if the COM component is to be used across the network, there has to be a entry in the registry of each machine that the component has to be called from. Then, of course there is the problem of the DLL HELL, which occurs when the application stops working because of the compatibility problems in the different versions of the component. These were the issues that Microsoft attempted to tackle when they designed Assemblies.
With Assemblies, there is no need for registry entries. Since assemblies are self describing, so the information does not have to be maintained else where. Hence the process of installing a component is simply copying the assembly file in the application folder. But then there is no centralized record of all the components which was the motive of maintaining the information in the registry. With private assemblies, there is no need to keep a centralized record since these assemblies were not meant to be used publicly or shared between applications. With Shared assemblies, all the components are kept in a single folder on the system, so getting the information of all the shared assemblies on a system is as simple as seeing the contents of a folder.
Creating multi file assemblies reduces the working set of the application when it is being called which helps in performance improvement because the .NET runtime loads only the required modules.
With Shared Assemblies, the problem of DLL HELL is also solved because the assembly is identified not only by it's name but also it's version number hence it is possible to have an assembly of different versions lying in the assembly cache. When the client calls a assembly, it indicates the name and the version number of the same so there is no problems on the call being relayed to the right assembly. The versioning and the simultaneous installs of multiple versions apply only to Shared assemblies and not private assemblies since there is no point in having multiple versions of a private assembly, which is being called on only by a single application.