Skip to main content

Disquistion of .NET Architecture


What is .NET?

This is a loaded question, but what it really comes down to is that .NET means different things to different people. Much of what Microsoft is now offering has the .NET name somewhere in its title, but what .NET means really depends on whom you ask. The official one-line answer is that .NET is Microsoft’s platform for XML Web services.

Microsoft’s .NET Framework is a new computing platform built with the Internet in mind, but without sacrificing the traditional desktop application platform. The Internet has been around for a number of years now, and Microsoft has been busy developing technologies and tools that are totally focused on it. These earlier technologies, however, were built on Windows DNA (Distributed interNet Applications Architecture), which was based on COM (Component Object Model). Microsoft’s COM was in development many years before the Internet became the force that we know today. Consequently, the COM model has been built upon and added to in order to adapt it to the changes brought about by the Internet.

With the .NET Framework, Microsoft built everything from the ground up with Internet integration as the goal. Building a platform from the ground up also allowed the .NET Framework developers to look at the problems and limitations that inhibited application development in the past and to provide the solutions that were needed to quickly speed past these barriers.


.NET is a collection of tools, technologies, and languages that all work together in a framework to provide the solutions that are needed to easily build and deploy truly robust enterprise applications. These .NET applications are also able to easily communicate with one another and provide information and application logic, regardless of platforms and languages.


Architecture of .NET

The .NET provides you with a wide variety of tools such as compilers, debuggers, programming languages, and execution engine (named CLR – Common Language Runtime), developer tools, and a large number of predefined building blocks libraries. Those libraries are named FCL (Framework Class Libraries). You can think each .NET component as building block in a house, as illustrated in this image.





First look at the beige component on the right side of the house. It is not part of the .NET Framework, but it touches the .NET Framework at all the levels. The doorknob on this component indicates that through this application, you can develop applications that allow you to touch all the components of the .NET Framework.

Second, notice that Common Language Runtime (CLR) is the primary part of the house’s foundation. It’s a crucial part of the foundation because it’s engine that loads and manages the execution of source code. All other services you need to develop applications are on top of the CLR. I will discuss all these components one-by-one, but not separately, but as whole process and how each component assists your application to become ready.

Compiling Source Code into Managed Modules

So I hope you have already decided to work on .NET Framework as your platform to build an application. Great! Now your first step should be that what type of application or component you aim to build.

Next step is to decide which programming language you will use to build your application or component. Actually, this task is very hard because you must know which language provides what features. For example, in unmanaged C/C++, you have pretty low-level control of the system. Here, you can manage memory exactly the way you want to, create threads easily if you need, and so on. But on the other side, VB.NET allows you to create very rich UI (User Interface) applications very rapidly and also permits you to easily control COM objects.

If you use the .NET Framework, your code targets the Common Language Runtime (CLR), which affects your decision about a programming language you have selected. The CLR is just what its name says it is: A runtime that is common for all .NET compatible languages. The features of CLR are available to any and all programming languages that target it – period. If the runtime allows you to create a thread, then any language of .NET Framework can do the same task, if the runtime uses exceptions to report errors, then all languages get error reported via exceptions.

In fact, at runtime, the CLR has no conception which programming language the developer had used for the source code. This means that you should choose the programming language that fulfills your requirements without worrying anything else. You can develop your code in any language, but the condition is the programming language you have chosen must target to CLR.

So if what I say is true, then what are the benefits of using one programming language over another? Well, I think of compilers as syntax checkers and correct code analyzers. They check your source code and ensure that whatever you’ve written makes some sense. Simply put, different programming languages allow you to develop using different syntax. Don’t underestimate the value of this. If you are building mathematical or financial applications, expressing your intentions using APL syntax can save many days of development time when compared to expressing the same intention using Perl syntax, for example.

Microsoft is continuously creating language compilers that target the runtime: C++ with managed extensions, C# (pronounced “C sharp”), Visual Basic.NET, Jscript, Java, and an intermediate language (IL) Assembler. In addition to Microsoft, there are several other companies creating compilers that produce code that targets the CLR. At this writing, I am aware of compilers for Alice, APL, and COBOL.

The figure shown below shows the process of compiling source code files:



As the figure shows, you can create source code files using any programming language that supports the CLR. Then, you use the corresponding compiler to check syntax and analyze the code. Regardless of which compiler you use, the consequence is a managed module. A managed module is a standard Windows portable executable (PE) file that requires the CLR to execute. In the future, other operating systems (OS) may use the PE file format as well.

A managed module is composed of the following parts:

PE header

·         It is the standard Windows PE file header, which is similar to the Common Object File Format (COFF) header.
·         The PE header indicates the type of file - - GUI, CUI or DLL - - and also has a timestamp indicating when the file was built.
·         For modules that contain only IL code (Intermediate Language Code), the bulk of the information in the PE header is ignored.
·         For modules that contain native CPU code, this header contains information about the native CPU code.

CLR header

·         This header contains the information (interpreted by the CLR and utilities) that makes this a managed module.
·         It includes the version of the CLR required, some flags, the MethodDef metadata token of the managed module’s entry point method (main method), and the location/size of the module’s metadata, resources, strong name, some flags, and other less interesting stuff.

Metadata

Every managed module contains metadata tables, of which there are 2 main types: those that describe the types and members defined in your source code, and those that describe the types and members referenced by your source code.

Intermediate Language (IL) code

This is the code that was produced by the compiler as it compiled the source code. IL is later compiled by the CLR into native CPU instructions.


Most compilers of the past produced code targeted to a specific CPU architecture, such as x86, IA64, Alpha, or PowerPC. All CLR-compliant compilers produce intermediate language (IL) code instead. IL code is sometimes referred to as managed code, because its lifetime and execution are managed by the CLR.

In addition to producing IL, every compiler targeting the CLR is required to produce full metadata into every managed module. In brief, metadata is simply a set of data tables that describes what is defined in the module, such as types and their members. In addition, metadata also has tables indicating what the managed module references, such as imported types and their members. Metadata is always companion with the file that contains the IL code. In fact, the metadata is always embedded in the same EXE/DLL as the code, making it impossible to separate the two. Since the metadata and code are produced by the compiler at the same time and are bound into resulting managed module, the metadata and the IL code it describes are never out of sync with one another.

Metadata has many uses. Here are some of them:

·         Metadata removes the need for header and library files when compiling, because all the information about the referenced types/members is contained in one file along with IL that implements those type/members. Compilers can read metadata directly from managed modules.
·         Visual Studio uses metadata to help you write code. Its IntelliSense feature parses metadata to tell you what methods a type offers and what parameters that method expects.
·         The CLR code verification process uses metadata to ensure that your code performs safe operations.
·         Metadata entitles the garbage collector to track the lifetime of objects. For any object, the garbage collector can determine the type of the object, and from the metadata it knows which fields within that object refer to other objects.

Four of the compilers that Microsoft offers – C#, Visual Basic, Jscript, F# and the IL Assembler – always produce managed modules, which require the CLR to execute. That is, end users must have the CLR installed on their machines in order to execute any managed modules.

The Microsoft C++ compiler, by default, builds unmanaged modules: the EXE or DLL files with which we are familiar. These modules don’t require the CLR in order to execute. However, by specifying a new command-line switch, the C++ compiler can produce managed modules that do require the CLR to execute. Of all the Microsoft compilers cited, C++ is unique in that it is the only language that allows the developer to write both managed and unmanaged code and have it emitted into a single managed module. This can be a great feature because it allows developers to write the bulk of their applications in managed code (for type-safety and component interoperability) but continue to access their existing unmanaged C++ code.


Combining Managed Modules into Assemblies

The CLR doesn’t actually work with modules; it works with assemblies. An assembly is an abstract concept, which can be difficult to grasp at first. First, an assembly is a logical grouping of one or more managed modules or resource files. Second, an assembly is the smallest unit of reuse, security, and versioning. Depending on the choices you make with your compilers or tools, you can produce a single-file assembly or you can produce a multi-file assembly.

The figure below should help explain what assemblies are about:







In this figure, we are passing the file names of some managed modules and resource (or data) files to a tool. This tool produces a single PE file that represents the logical grouping of files. This PE file contains a block of data called the manifest, which is simply another set of metadata tables.

The manifest contains all the information about the items in the assembly, including what parts of the assembly are exposed to the outside world. The manifest also lists the assembly’s dependencies on other assemblies. Each assembly is required to have a manifest.

The manifest can be a part of PE file, or it can be a standalone file if your assembly has more than one file in it. Although this is not an exhaustive list, a manifest contains:

·         Assembly name
·         Version
·         Files in the assembly
·         Referenced assemblies

In addition, a developer can set custom attributes for an assembly, such as title and description.

By default, compilers actually do the work of turning the emitted managed module into an assembly. That is, the C# compiler emits a managed module that contains a manifest. The manifest indicates that the assembly consists of just one file. So for projects that have just one managed module and no resource files, the assembly will be the managed module, and you don’t have any additional steps to perform during your build process. If you wish to group a set of files into an assembly, then you will have to be aware of more tools (such as the assembly linker, AL.exe) and their command-line options.

The modules in an assembly also encompass information, including version numbers, about referenced assemblies. This information makes an assembly self-describing. In other words, the CLR knows everything that an assembly needs in order to execute. No additional information is required in the registry or in the Active Directory, so deploying assemblies is much easier than deploying unmanaged components.

Global Assembly Cache

Even thought components in .NET do not have to be registered, there is a similar process if you have an assembly that is used by multiple applications. The CLR actually has two caches within its overall code cache: the download cache and the Global Assembly Cache (GAC). An assembly that will be used by more than one application is placed into the global assembly cache by running an installer that places the assembly in the GAC. Tool left. If an assembly is not in the local directory and not in the GAC, you can have a codebase hint in a configuration file. The CLR then downloads the assembly, storing it in the download cache and binding to it from there. This download cache is just for assemblies that have to be downloaded.

The GAC is where you place a component if you want multiple applications to use the same component. This is very similar to what you have with registered COM components.

Placing assemblies in the GAC has several advantages. Assemblies in the GAC tend to perform better because the runtime locates them faster and the security does not have to be checked each time that the assemblies are loaded. Assemblies can be added to or removed from the GAC only by someone with administrative privileges.

Where things get interesting is that you can actually have different versions of the same assembly in the GAC at the same time. Notice that I have avoided saying registered in the GAC because you are not placing anything in the registry. Even if a component is running in the GAC, you can add another version of the same component running alongside it, or you can slipstream in an emergency fix. This is all based on the version number and you have control over whether an update becomes a newly running version or merely an upgrade to an existing system. Assemblies can be placed in the GAC only if they have a shared name.

Executing the Code in Your Assembly

As cited earlier, managed modules contain both metadata and IL code. IL is a CPU independent machine language created by Microsoft after consultation with several external commercial and academic language/compiler writers. IL understands object types and has instructions that create and initialize objects, call virtual methods on objects, and manipulate array elements directly. It even has instructions that throw and catch exceptions for error handling. You can think of IL as an object-oriented machine language.

Usually, developers prefer to program in a high-language, such as C# or Visual Basic.NET. the compilers for all these high-level languages produce IL. However, like any other machine language, IL can be written in assembly language and Microsoft does provide an IL assembler, ILAsm.exe. Microsoft also provides an IL disassembler, ILDasm.exe.

Note:

Some people are concerned that IL does not offer enough intellectual property protection for their algorithms. In other words, you could build a managed module and someone else could use a tool, like IL disassembler, to reverse engineer exactly what your application code does.

Yes, it’s true that IL code is higher-level than most other assembly languages and, in general, reverse engineering IL code is relatively simple. However, when you implement a web service or web form application, your managed module resides on a server, inaccessible to anyone outside your company. Outsiders cannot use any tool to see the IL code, so your intellectual property is completely safe.

If you are concerned about any of your managed modules that you do distribute, then you can use the Microsoft obfuscator utility (OB.exe), which is downloadable from http://www.GotDotNet.com. This utility scrambles the names of all the private symbols in your managed module metadata. It will be difficult for someone to unscramble the names and understand the purpose of each method. Note that the Microsoft obfuscator scrambles metadata names only and does not scramble the IL code in any way since the CLR must be able to process unscrambled IL.

If you don’t feel that the obfuscator offers the kind of intellectual property protection that you desire, then you can consider implementing your more-sensitive algorithms in some unmanaged module, which will contain native CPU instructions instead of IL and metadata. Then, you can use the CLR’s interoperability features to communicate between the managed and unmanaged portions of your application. Of course, this assumes that you’re not worried about people reverse engineering the native CPU instructions in your unmanaged code.


Any high-level language will most likely expose only a subset of the facilities offered by the CLR. IL assembly language, however, gives a developer access to all the facilities of the CLR. So if your programming language of choice hides a CLR feature that you really wish to take advantage of, you can write that portion of your code in IL assembly or in another programming language that exposes the CLR feature you seek.

An important thing to note about IL is that it is not tied to any specific CPU platform. This means that a managed module containing IL can run on any CPU platform as long as the operating system running on that CPU platform hosts a version of the CLR. Of course, IL instructions cannot be executed directly by today’s CPUs (although this may change someday). In order to execute a method, its IL code must first be converted to native CPU instructions. To make this conversion, the CLR provides a JIT (just-in-time) compiler.

The figure below shows what happens the first time a method is called.







Just before the Main method executes, the CLR detects all the types (classes) that are referenced by the code in Main. This causes the CLR to allocate an internal data structure that is used to manage access to each referenced type. In the figure above, the Main method refers to a single type, Console (Console is a class and writeline is a method), causing the CLR to allocate a single internal structure. The internal data structure contains an entry for each method defined by the type (here both the methods are same: writeline()). Each entry holds the address where the method implementation can be found. When initializing this structure, the CLR sets each entry to a function contained inside the CLR itself. I call this function JITCompiler.

When Main makes first call to Writeline, the JITCompiler function is called. The JITCompiler function is responsible for compiling a method’s IL code into native CPU instructions. When called, the JITCompiler function knows what method is being called and what type defines this method. The JITCompiler verifies and compiles the IL code into native CPU instructions, which are then saved in a dynamically allocate block of memory. JITCompiler goes back to the type’s internal data structure and replaces the address of the called method with the address of the block of memory containing the native CPU instructions. Finally, JITCompiler jumps to the code in the memory block.

Suppose now that Main calls Writeline a second time. This time, because the code for Writeline has already been verified and compiled, the call goes directly to the native code in the memory block, skipping the JITCompiler function entirely. After the Writeline method executes it returns to the Main. The figure below shows what the situation looks like when Writeline is called the second time:





The important thing to note is that the process incurs a performance hit only the first time a method is called. All subsequent calls to the method execute at the full speed of the native code: Verification and compilation to native code is not performed again.

Note that the JIT compiler stores the native CPU instructions in dynamic memory: The compiled code is discarded when the application terminates. So if you run the application in the future or if you run two instances of the application simultaneously (in two different operating system processes), then the JIT compiler will have to compile the IL to native instructions again.

Developers coming from unmanaged C or C++ background are probably thinking about the performance ramifications of all this. After all, unmanaged code is compiled for a specific CPU platform, and when invoked, the code can simply execute. In this managed environment, compiling the code is accomplished in two phases. First, the compiler passes over our source code, doing as much work as possible in producing IL. But then, in order to actually execute the code, the IL itself must be compiled into native CPU instructions at run time, requiring that more memory be allocated and requiring addition CPU time to do work.

In fact, hard as this might be to believe, many people (including me) think that managed applications could actually out-perform unmanaged applications. For example, when the JIT compiler compiles the IL code into native code at runtime, the compiler knows more about the execution environment than an unmanaged compiler would know. Here are some ways that managed code could out-perform unmanaged code:

·         A JIT compiler could detect that the application is running on Corei7 (or any processor) and produce native code that takes advantage of any special instructions offered by the Corei7.

·         A JIT compiler could detect that a certain test is always false on the current host machine. For example, a method with code like this:

If (numberOfCPUs > 1)
{
………..
}

could cause the JIT compiler to not generate any CPU instructions for the above code if the host machine has only 1 CPU. In this case, the native code has been fine-tuned for the host machine: the code is smaller and executes faster.


IL and Verification

IL is stack-based, which means that all its instructions push operands onto an execution stack and pop results off the stack. Accordingly, IL offers no instructions to manipulate registers. And here’s another simplification: IL instruction are typeless. For example, IL offers an add instruction that adds the last two operands pushed on the stack. IL does not offer a 32-bit add instruction and a 64-bit add instruction. When the add instruction executes, it determines the types of the operands on the stack and performs the appropriate operation.

In my opinion, the biggest benefit of IL is not that it abstracts away the underlying CPU. The biggest benefit is application robustness. While compiling IL into native CPU instructions, the CLR performs a process called verification. Verification examines the high-level IL code and ensures that everything it does is safe. For example, verification checks that no memory is read from without having previously been written to, that every method is called with the correct number of parameters, that each parameter is of the correct type, that every method’s return value is used properly, that every method has a return statement, and so on.

The metadata for each managed module incorporates all the method and type information used by the verification process. If the IL code is determined to be unsafe, then a System.Security.VerificationException exception is thrown, prohibiting the method from executing.

In Windows, each process has its own virtual address place. Separate address spaces are necessary because Windows can’t trust the application code. It is entirely possible (and unfortunately, all too common) that an application will read from or write to an invalid memory address. Placing each Windows process in a separate address space enhances robustness: One process cannot adversely affect another process.

However, by verifying the managed code, we know that the code does not improperly access memory and cannot adversely affect another application’s code. This means that we can run multiple managed applications in a single Windows virtual address space.

Because Windows processes require a lot of operating system resources, launching many processes can hurt performance and limit available OS resources. Running multiple applications in a single OS process wanes the number of processes, which can improve performance, require fewer resources, and offer equivalent robustness. This is another benefit of managed code as compared to unmanaged code.

Diagram can be made for above line.

The CLR does, in fact, offer the ability to execute multiple managed applications in a single OS process. Each managed application is called an AppDomain. By default, every managed EXE will run in its own separate address space that has just one AppDomain. However, a process hosting the CLR (such as IIS or a future version of SQL Server) can decide to run AppDomains in a single OS process.

The .NET Framework Class Library

Included with the .NET Framework is a set of Framework Class Library (FCL) assemblies that contains several thousand type definitions, where each type exposes some functionality. All in all, the CLR and the FCL entitle developers to build the following kinds of applications:



·         Web Services – Components that can be accessed over the Internet very easily. Web services are, of course, the main thrust of Microsoft’s .NET initiative. Web services entitle different applications from different sources to communicate with each other without time-consuming custom coding, and because all communication is in XML, Web services are not tied to any one operating system or programming language. For example, Java can talk with Perl, Windows applications can talk with UNIX applications.

·         Web Forms – HTML-based applications (web sites). Typically, web form applications make database queries and web service calls, combine and filter the returned information, and then present that information in a browser using a rich HTML-based UI.

·        Windows Forms – Rich Windows GUI applications. Instead of using a web form to create your application’s UI, you can use the more powerful, higher-performance functionality offered by the Windows desktop. Windows form applications can take advantages of controls, menus, mouse and keyboard events, and can talk directly to the underlying operating system. Like web form applications, Windows form applications make database queries and call web services.

·         Windows Console Applications – For applications with very simple UI demands, a console application provides a quick and easy solution. Compilers, utilities, and tools are typically implemented as console applications.

·        Windows Services – Yes, it is possible to build service applications controllable via the Windows Service Control Manager (SCM) using the .NET Framework. There are two types of services you can create using the .NET Framework. Services that are the only service in a process are assigned the type Wind32OwnProcess. Services that share a process with another service are assigned the type Win32ShareProcess.

·        Component Library – Of course, the .NET Framework allows you to build stand-alone components (types) that may be easily included into any of the above mentioned application types.

Note:

These are not the only applications that we can develop, but as I have cited in .NET Framework 4.0 that we can make applications like WPF, Office and many more. These above mentioned are just the major applications which we use more.

Since the FCL contains literally thousands of types, a set of related types is presented to the developer within a single namespace. For example, the System namespace (which you should become most familiar with) contains the Object base type, from which all other types eventually derive. In addition, the System namespace contains types of integers, characters, strings, exception handling, and console I/O, as well as a bunch of utility types that convert safely between data types, format data types, generate random numbers, and perform various math functions. All applications use types from the System namespace.

To access any platform feature, you need to know which namespace contains the types that expose the facility you’re after. If you want to customize the behavior of any type, you can simply derive your own type from the desired FCL type. The .NET Framework relies on the object-oriented nature of the platform to present a consistent programming paradigm to software developers. It also enables developers to create their own namespaces containing their own types, which merge seamlessly into programming paradigm.

Most of the namespaces in the FCL present types that you can use for any kind of application. The table below lists some of the more general namespaces, with a brief description of what the types in that namespaces are used for:




Namespace
Purpose of Types
System
All the basic types used by every application.
System.Collections
Managing collections of objects. Includes the popular collection types such as Stack Queues, Hashtables and so on.
System.Diagnostics
Instrumenting and Debugging your application.
System.Drawing
Manipulating 2D graphics. Typically used for Windows Forms applications and for creating images that are to appear in a web form
System.EnterpriseServices
Managing transactions, queued components, object pooling, just-in-time activation, security, and other features to make the use of managed code more efficient on the server.
System.Globalization
National Language Support (NLS), such as string compares, formatting, and calendars.
System.IO
Doing stream I/O, walking directories and files.
System.Management
Managing other computers in the enterprise via WML.
System.Net
Network communication
System.Reflection
Inspecting metadata and late binding to types and their members.
System.Resources
Manipulating external data sources.
System.Runtime.InteropServices
Enabling managed code to access unmanaged OS platform facilities, such as COM components and functions in Win32 DLLs.
System.Runtime.Remoting
Accessing types remotely
System.Runtime.Serialization
Enabling instances of objects to be persisted and regenerated from a stream.
System.Security
Protecting data and resources
System.Text
Working with text in different encodings, like ASCII or Unicode.
System.Threading
Performing asynchronous operations and synchronizing access to resources.
System.XML
Processing XML schemas and data.


You should be aware, however, that in addition to supplying the more general namespaces, the FCL offers namespaces whose types are used for building specific types. The table below lists some of the application-specific:


Namespace
Purpose of Types
System.Web.Services
Building web services.
System.Web.UI
Building web forms.
System.Windows.Forms
Building Windows GUI applications.
System.ServiceProcess
Building a Windows service controllable.




The Common Type System

By now, it should be obvious to you that the CLR is all about types. Types expose the functionality to your applications and components. Types are the mechanism by which code written in one programming language can talk to code written in a different programming language. Because types are at the root of the CLR, Microsoft created a format specification- the common type system (CTS)-that describes how types are defined and behave. The CTS specification states that a type (class) may contain zero or more members.

·         Field – A data variable that is part of the object’s state. Fields are identified by their name and type.

·         Method – A function that performs an operation on the object, often changing the object’s state. Methods have a name, signature, and modifiers. The signature specifies the calling convention, number of parameters (and their sequence), the types of the parameters, and the type of value returned by the method.

·         Property – To the caller, this member looks like a field. But to the type implementer, this member looks like a method (or two). Properties allow an implementer to validate input parameters and object state before accessing the value and to calculate a value only when necessary; they also allows a user of the type to have simplified syntax. Finally, properties also allow you to create read-only or write-only fields.

·         Event – A notification mechanism between an object and other interested objects. For example, a button could offer an event that notifies other objects when the button is clicked.

The CTS also specifies the rules for type (class) visibility and for access to the members of a type. For example, marking a type as public exports the type (means any type can access this type), making it visible and accessible to any assembly. On the other hand, marking a type as assembly (called internal in C#) makes the type visible and accessible to code within the same assembly only. Thus, the CTS establishes the rules by which assemblies form a boundary of visibility for a type, and the runtime enforces the visibility rules.

Regardless of whether a type is visible to a caller, the type gets to control whether the caller has access to its members. The following shows the valid options for controlling access to a method or field:

·         Private – Callable only by other methods in the same class type.
·         Family – Callable by derived types, regardless of whether they are within the same assembly. Note that many languages (like C++, and C#) refer to family as protected.
·         Family and Assembly – Callable by derived types, but only if the derived type is defined in the same assembly.
·         Assembly – Callable by any code in the same assembly. Note that many languages refer to assembly as internal.
·         Family or Assembly – Callable by derived types in any assembly and by any types in the same assembly. Note that C# refers to family or assembly as protected internal.
·         Public – Callable by any code in any assembly.

In addition, the CTS defines the rules governing type inheritance, virtual functions, object lifetime, and so on. These rules have been designed to accommodate the semantics expressible in modern programming languages. In fact, you won’t even need to learn the CTS rules, because the language you use exposes its own language syntax and type rules in the same way you are familiar with today; it maps the language specific syntax to the language of the CLR when it emits the managed module.

When I first started working with the CLR, I soon realized that it is the best to think of the language and the behavior of your code as two separate and distinct things. Using C++, you can define your own types with their own members. Of course, you could have used C# or Visual Basic.NET to define the same type with the same members. Sure, the syntax you use for defining this type is different depending on the language you choose, but the behavior of the type will be absolutely identical regardless of the language because the CLR – by means of the CTS – defines the behavior of the type.

To help make this clear, let me give you an example: The CTS supports single inheritance only. The C++ language supports types that inherit from multiple base types: nevertheless, the CTS cannot accept and operate on any such type. To help you, the Visual C++ compiler reports an error if it detects that you’re attempting to create managed code that includes a type inherited from multiple base types.

Here’s another CTS rule: All types must (ultimately) inherit from a predefined type, System.Object. As you can see, Object is the name of a type defined in the System namespace. This Object is the root of all other types and therefore guarantees every type instance has a minimum set of behaviors. Specifically, the System.Object type allows you to:

·         Compare two instances for equality
·         Obtain a hash code for the instance
·         Query the true type of an instance
·         Perform a shallow (bitwise) copy of the inheritance
·         Obtain a string representation of the instance’s object’s current state


The Common Language Specification

It integrates all languages to let objects created in one language be treated as equal citizens by code written in a completely different language. To make this possible, the CLR defines a standard behavior for types, embeds self-describing type information (metadata), and provides a common execution environment.

Language integration is a fantastic goal, of course, but the truth of the matter is that programming languages are very different from one another. For example, some languages lack features commonly used in other languages:

·         Case sensitive
·         Unsigned integers
·         Operator overloading
·         Methods that support a variable number of parameters

If you intend to create types that are easily accessible from other programming languages, then it is important that you use only features of your programming language that are guaranteed to be available in all other languages. To help you with this, Microsoft has defined a common language specification (CLS) that details for compiler vendors the minimum set of features that their compilers must support if they are to target the runtime.

Note that the CLR/CTS supports a lot more features than the subset defined by the common language specification, so if you don’t care about language interoperability, you can develop very rich types limited only by the capabilities of the language. Specifically, the CTS defines rules to which externally visible types and methods must adhere if they are able to be accessible from any CLR-compliant programming language. Note that the CLS rules do not apply to code that is only accessible within the defining assembly. The figure below summarizes the way in which language features overlap with the CLS, within the wider context of the CLR/CTS.




As this figure shows, the CLR/CTS offers a broadly inclusive set of features. Some languages expose a large subset of the CLR/CTS; in fact, A programmer willing to write in IL assembly language is able to use all the features offered by the CLR/CTS. Most other languages – such as C#, VB, and Fortran – expose a subset of the CLR/CTS features to the programmer. The CLS defines a minimum set of features that all languages must support.

If you’re designing a type in one language and you expect that type to be used by another language, then you should not take advantage of any features that are outside of the CLS. Doing so means that your type members might not be accessible by programmers writing code in other programming languages.

In the code below, a CLS-compliant type is being defined in C#. However, the type has a few non-CLS compliant constructs that cause the C# compiler to complain about the code:

using System;

// Tell compiler to check for CLS Compliance
[assembly:CLSCompliant(true)]

//Errors appear because the class is public
public class App
{

// Error: Return type of ‘App.Abc()’ is not CLS-Compliant
public UInt32 Abc()
{
return 0;
}

// Error: Identifier ‘App.Abc()’ differing
// Only in case is not CLS-Compliant

public void abc()
{
}

// No error: Method is private
private UInt32 ABC()
{
return 0;
}
}

In the above code, the [assembly:CLSCompliant(true)] attribute is applied to the assembly. This attribute tells the compiler to ensure that any publicly exposed type has no construct that would prevent the type from being accessed from any other programming language. When the above code is compiled, the C# compiler emits two errors:

1.      The first error is reported because the method Abc returns an unsigned integer; Visual Basic.NET and some other languages cannot manipulate unsigned integer values. (But now, Microsoft provides unsigned integer data types in VB.NET in Visual Studio 2005 and its later versions. So just take this point as an example that what problems were faced by programmers when it was completely missing)
2.      The second error arises because this type exposes two public methods which differ only by case: Abc and abc. Visual Basic.NET and some other languages cannot call both of these methods.

Note that if you were to delete public from in front of class App and recompile, both errors would go away. The reason is that App type would default to internal and would therefore no longer be exposed outside the assembly.

Security

One of the runtime’s main benefits is that an entire security infrastructure is built right in. In fact, two major security models are set up in the .NET Framework: code access security and role-based security.

Code Access Security

This security does not control who can access the code; rather, it controls what the code itself can access. This is important because it allows you to build components that can be trusted to varying degrees. If you build a VB component today and want to perform database access, you are free to call ADO and connect to a database (provided, of course, that you have a valid user ID and password). With .NET, however, you can specify, with the tools in the .NET Framework, what actions your component can and, more importantly, cannot perform. This has the benefit of preventing others from using the code in ways that you did not intend.

Perhaps the main benefit of CAS is that you can now trust the code that is downloaded from the Internet. Security can be set up so that it becomes impossible for the code to perform any mischievous actions. This would prevent most of the macro viruses that spread via e-mail today.

Role-based Security          

Role-based security is the same type of security you get when you use MTS or COM+ Component Services. In .NET, the Framework determines the caller, called a principal, and checks the principal’s individual and group permissions. Unlike COM/COM+ role-based security, however, .NET cannot make an assumption that the user will have a valid NT user account and token to pass in. Therefore, .NET allows for generic and custom principals, as well as standard Windows principals. You can define new roles for each application if you want.



Compiled By: Chaudhary Amit V.

Comments

  1. Amit stile i have confusing when we import pre-requises in our setup then it come direct or convert them also in assembly with setup . . .
    and in which level (mean CLR level or when it make Assembly level .exe file at that time ).

    ReplyDelete

Post a Comment

Popular posts from this blog

Characteristics of a Good Programming Language

Till now there are many high level languages which are very popular, and there are others, which could not become so popular in-spite of being very powerful. There might be many reasons for the success of a language, but one obvious reason is the characteristics of the language. Several characteristics believed to be important with respect to making a programming language good are briefly discussed below. Simplicity A good programming language must be simple and easy to learn and use. For example, BASIC is liked by many programmers only because of its simplicity. Thus, a good programming language should provide a programmer with a clear, simple and unified set of concepts which can be easily grasped. It is also easy to develop and implement a compiler or an interpreter for a programming language that is simple. However, the power needed for the language should not be sacrificed for simplicity. The overall simplicity of a programming language strongly affects the readability of the pr...

Angular 4 and Firebase Authentication: Email/Password

In our  previous  article we saw how to create authentication module using Google identity provider. Now we will see how to implement Email and Password authentication using Firebase. We will use Bootstrap form to create intuitive user interface for sign-up and login using Email and Password. Step 1: Create signUp component. ng generate component signUp Step 2: Create custom form in sign-up.component.html file. The result of above code: Step 3: Add two functions for creating the user and login using Email and Password in src/app/providers/AFAuth.ts file. Step 4: Call createUserWithEmailAndPassword function in service from sign-up.component.ts. Step 5: Update routing configuration in app.module.ts  to include signUp component. Step 6: Update Login form to have Bootstrap form. The result of the above code. Step 7: Enable Email/Password component in Firebas...

Angular 4 and Firebase Authentication: Setup

If you have come to this article, it means you are keen to learn new technology and that too Firebase. I love Firebase because it provides all basic but important features of any web application. Take for example, authentication, which is cumbersome and risky if not implemented with utmost care. And when we have the integration of Angular and Firebase, it becomes a lot easier for a developer to build such crucial modules in less time with minimal efforts. In this article we will create a simple Angular application using Firebase. I am going ahead with the understanding that you know the benefits of Firebase and have little knowledge about it. There are plenty of posts out on the web if you are behind. Step 1: Install Angular CLI (if not installed). npm install -g angular-cli Step 2: Create new Angular 4 project. By default now angular CLI will create Angular 4 project so you need not fret. ng new firebase-authentication Step 3: Check whether the ne...