In the last post, we introduced problems that motivated us toward investigating the .NET framework solution. In fact, Microsoft implemented the targeted points, we previously mentioned, in a very smart way. That’s what we are going to explain in this point.
.NET Building blocks
Microsoft .NET framework has a very structured strategy that simplifies the process of achieving the goals. As shown in the above figure, it’s build in three major blocks: the Common Language Run-time, the Common Type System and the Common Language Specification. We will discuss each one in some details.
- Common Type System (CTS):
Each programming language designer has to specify a very important property of it, which is called type system. The type system indicates which data type are supported by this programming language (e.g. integers, chars, floats,..etc.) and what operations we can do on it. This allows us to detect errors when dealing with data. For example, doing illegal operation on some data types (e.g. adding two booleans).
In MS .NET platform, CTS specification fully describes all possible data types and programming constructs supported by the run-time. That is, to design a language that is aware-of .NET, it has to support its type system according to the CTS specifications. CTS specifies how entities interact with each other and how they are represented in the .NET metadata format. That is, how objects are communicating with each other through messages and how this is defined in the metadata (discussed very soon).
However, some .NET languages may not support every feature defined by the CTS. So, for a language to be type safe, we have to provide another alternative to the CTS, which is the Common Language Specification.
- Common Language Specifications (CLS):
CLS is a set of rules that describes, in detail, the minimal and complete set of features a given .NET-aware compiler must support to produce code that can be hosted by the CLR, while at the same time can be accessed in a uniform manner by all languages that the .NET platform support. In other words, CLS is a subset of the full functionality of CTS.
- Common Language Run-time (CLR):
The core of the .NET platform is the Common Language Run-time, aka CLR. It do all the heart tasks of locating, loading and managing .NET types. This is a very important task to be done by the CLR, as it guarantees that the written types will function properly according to what is defined in the CLS (or CTS). CLR has a very important module called the Garbage Collector. The GC is the one responsible for managing memory locations, and hence no more manual memory management. CLR also provides application hosting services. That is, rather than running the code directly in the machine, the CLR is now responsible for running applications, and hence any platform that has a CLR can run the application (platform-independence). Moreover, the CLR handle threading in a very efficient manner allowing us to develop parallel modules very easily. CLR performs some security checks that guarantee access levels and execution privileges.
The key assembly in CLR is mscore.dll, which contains a large number of types, that encapsulate a wide variety of common programming tasks as well as the core data types used by all .NET languages. The role of mscore.dll comes also when an assembly is referenced for use, mscore.dll is loaded automatically which in turn loads loads the required assembly. This is known as MS Common Object Run-time Execution Engine). Not only does mscore.dll manage these tasks, but also it’s also responsible for creating custom types. That is, when we define a new type (e.g. a class, structure,…etc.), the CLR (specifically mscore.dll) creates it for you.
To summarize all these previous blocks, we can define the relationship between the three blocks as in the below figure
.NET Base Class Library
In addition to the CLR and CTS/CLS specifications, the .NET platform provides a base class library that is available to all .NET programming languages. As in the previous state, we mentioned MFC and ATL, in the .NET we have the Base Class Library.
The Base Class Library has too many services, but we can summarize them in the above figure.
– Database Access: Handling databases is one of the most important issues that we face in every software application. The base class library provides us with a rich set of classes that are very easy to use with databases. Microsoft provides us with Active Data Objects ADO which allows us to access local and remote relational databases. ADO is extended in the .NET platform to be ADO .NET, which is more powerful.
– Desktop GUI APIs: To build applications that have a rich graphical user interface, we use the predefined APIs available in the .NET class library. It’s very easy, now, to build applications that are even-driven using .NET features. Recently, Microsoft released Windows Presentation Foundation (WPF) to support more graphical interface features.
– Security: These collection of classes enables us to perform security checks against some critical issues. For example, accessing low-level system privileges.
– Remoting APIs: are used in accessing remote devices in a secure manner. Not only providing access, but also control of devices remotely.
–Threading: Building multi-threaded applications is now very easy using the collection of threading APIs. It also can control thread synchronization.
– File I/O: opening, reading and writing files is very simple with this collection of classes.
– Web APIs: Building rich web applications is done using ASP.NET approach. It provides a very powerful implementation of handling client-server applications.
More and more class libraries are provided in the .NET framework. You can investigate them in the Microsoft Developers Network (MSDN).
Few lines above, we mentioned that .NET is a platform that support many languages. You can check all languages supported by the .NET from here. But, how this is actually implemented ?! That is, how the .NET provide a common run-time environment for all these languages ?!
This is done using a technique like the one above. Each .NET compiler produces the same output, the Intermediate Language (IL) code and metadata. This is grouped in what is called an assembly (*.dll or *.exe). Actually, compilers can’t produce that same assembly without sharing the same CLR and CTS/CLS provided by the .NET.
The question now is: what is the content of the IL and metadata that makes it possible to be used from any other .NET-aware language ?!
- CIL: The same as Java bytecode, source code is not directly compiled into machine instructions. Rather, it’s compiled to an intermediate language which will be run in the .NET environment. CIL is not compiled into machine instructions until absolutely necessary. You can view the CIL code of any assembly using either ildasm.exe or using Reflector. Just pass them the assembly file (*.dll or *.exe) you want to investigate and see the results.
- Metadata: describes in detail the characteristics of every type within the binary.
- Manifest: contains information about the current version of the assembly, culture information (localizing strings & image resources) and a list of externally referenced assemblies that are required for the proper execution of the program.
The above three data pieces may be organized in a single file or in a multi-files where its divided into modules.
And So …
All these features are combined together to draw the following scenario.
– write your source code in any language you like (for sure, must be .NET-aware).
– pass the code to the appropriate .NET compiler.
– an assembly file is generated, which contains: CIL, metadata and manifest.
– the .NET execution engine runs the target assembly and reference external classes using the Class Loader.
– Just In-Time Compiler (or Jitter) doesn’t convert a CIL code into machine instructions until it’s referenced.
– The platform instructions are then executed.
This scenario is summarized in the following figure
This ends up our introduction on the .NET Solution. We marked how the .NET platform provides us with a complete solution to all previous problems. It’s important to notice that .NET is improved every while. The last release is .NET 4.5 one.
– Running code on top of the .NET execution engine requires more system resources, as the engine is running during the life-time of the application.
– Managed bytecode can often be easier to reverse-engineer that native code. That is, using ildasm.exe or Reflector we can get back the CIL code and extract important data from it (like serial keys).
– The .NET framework currently does not provide support for calling Streaming SIMD Extensions (SSE) via managed code. SIMD Extensions are machine instructions that are used to perform the same operation on a group of data. This make the processor accomplish tasks faster. To use this technique under .NET, we have to use un-managed code.
– .NET framework specifications are not fully implemented except in Windows operating system. For example: .NET on top of linux distribution doesn’t support GUI APIs.
At the end of this simple introduction, it’s very useful to refer to “Pro C# 2010 and the .NET 4 platform By: Andrew Troelsen”. It’s a very powerful reference that set along side with Microsoft Developers Network (MSDN).
I’ll be very glad to receive your questions and feedback :).