The .NET Architecture

This article is a sample chapter from .NET Security Programming, written by Donis Marshall and published by Wiley.

.NET security is not an island of technology, but a slice of a larger entity called the .NET Framework. Basic understanding of the .NET Framework is required before attempting .NET security programming. This chapter presents the basic concepts of the .NET Framework architecture and programming. This is an overview and is not intended to replace the independent study required for a mastery of this subject. (For a comprehensive discussion on the .NET Framework from a developer’s perspective, I recommend .NET Framework Essentials by Thun L. Thai and Hoang Q. Lam, O’Reilly & Associates, February 2002.)

Microsoft .NET is not just a different spin on the Win32 operating model. Furthermore, despite reports to the contrary, it is not Java in wolf’s clothing. You will never understand or adequately explain .NET simply by comparing it to existing products. .NET is new. As such, .NET introduces a fresh operating modality and perspective on computing software and devices.

Are there similarities to Java? Are there similarities to Win32? Yes, but there are many more differences. Successfully programming in .NET requires embracing this new technology as new and fully understanding the many things that make .NET unique. When object-oriented languages were introduced, developers faced a similar challenge and, unfortunately, mindset. Many programmers quickly learned the syntax and ported their C application to C++ or SmallTalk. However, without the requisite understanding of object-oriented programming, these new applications were procedural programs draped in the syntax of an object-oriented language. Some developers invested the time to learn object-oriented programming—not just the syntax, but the philosophy and intent. Their resulting applications were true object-oriented programs that provided all the benefits envisioned for the new programming modality. Similarly, understanding the philosophy and architecture of .NET is essential for creating applications that offer new solutions. Some industry analysts assert that Microsoft has gambled the company on .NET. I would not agree. .NET does represent a massive investment. However, Microsoft is a diversified and multibillion dollar company with many products and a sizable market share in many segments of the software industry. In addition, Microsoft is no longer simply a software company, having expanded into many markets outside their traditional stronghold.

But recognizing that Microsoft is not teetering on a precipice named .NET does not diminish the importance of .NET. .NET does represent a new philosophy in product development. From .NET will emerge an entirely new family of products that will drive Microsoft sales into the stratosphere over the next 5 to 10 years. If the .NET initiative fails, or more likely is adopted slowly, Microsoft will recover and continue, although maybe with a little less luster. Importantly, .NET allows Microsoft to escape the Windows conundrum. Although Windows has been enormously successful, it is still a box. .NET helps Microsoft emerge from that box and develop applications for a universal audience. This new opportunity will fuel growth not just for Microsoft, but for software developers everywhere.

I attended the formal launch of Microsoft .NET at the Professional Developers Conference in Orlando, Florida several years ago. William Gates III (aka Bill) was the keynote speaker. Part of his speech included an entertaining video. The video portrayed .NET as a new standard that will allow software to run anywhere, at anytime, on any platform, and on devices large and small.

  • Anywhere. This has reported many times, but it is worth repeating: “Microsoft was late to realize the importance and then embrace the Internet.” Recently, Microsoft has been making up for that late start. .NET marks the next major step in that journey. The Internet is not an adjunct of .NET, but is interwoven seamlessly into the product. The Internet was planned, integrated, and implemented into .NET—including the embracing of open standards such as XML and HTTP. Essentially, any platform that offers a browser that understands XML or HTML is a potential .NET client.
  • Anytime. The Internet is open 7 days per week and 24 hours per day. The Internet never closes. Since .NET leverages the Internet, .NET applications such as a Web service are fully accessible at anytime.
  • Any platform. .NET is a multilanguage and multiplatform operating environment. Compare this to Java, which is single-language and multiplatform. .NET offers C#, Visual Basic .NET, and many more .NET-compliant languages. Programming in .NET does not require learning an entirely new language. To program to the Java Virtual Machine (JVM) requires learning the Java language. For many, this is a substantial drawback. The common language runtime is the common runtime of all .NET languages. In addition, Microsoft publishes the Common Language Infrastructure (CLI) document, which is a set of guidelines for creating a .NET common language runtime for any platform, such as Linux. To view one such initiative, visit In the future, developers can create .NET applications in Windows and run them in Linux, Unix, Macintosh, or any platform that offers a common language runtime.
  • Devices large and small. NET marks Microsoft’s first extensive support of open standards, even if it is rather tepid. Microsoft adopts HTTP, SMTP, SOAP, XML, and many more standards. This means that any device that supports these standards can actively participate in a .NET conversation. This will liberate personal digital assistants (PDAs), hand-held, and embedded devices. These devices lack the girth to run powerful applications, such as full-blown Microsoft Office. Using open standards, these devices can tap the power of a back-end server and run virtually any program. The embedded chip in your refrigerator could access Microsoft Word remotely, compose a grocery list, and print it to a networked printer. Refrigerators with word-processing capabilities—way cool!

.NET Is Web Enabled

Microsoft .NET is Web empowered. Developers can use ASP.NET, XML Web services, and ADO.NET to easily create feature-rich Web applications. This represents the front, middle, and bottom tier of an n-tiered enterprise application. Despite this, do not believe the rhetoric stating that Microsoft has abandoned client-side applications—some applications will never be well suited for server-side operations. Windows Forms, a new forms generation engine, and other additions in the .NET Framework make development of traditional Windows applications more intuitive, while adding additional features.

.NET Components

.NET introduces a new component model that is largely implicit. The messiness of COM (Component Object Model) is removed. In .NET, developers use standard language syntax to create, publish, and export components. There is nothing else to learn. .NET addresses many of the shortfalls of COM, including susceptibility to DLL Hell, language incompatibilities, reference counting, and more.

Coding COM at the API level is exacting. Interfaces such as IUnknown, IDispatch, IConnectionPoint, and system functions such as CoGetClassObject and CoFreeUnusedLibraries represent a massive learning curve. MFC (Microsoft Foundation Classes), ATL (Active Template Library), and Visual Basic provided some relief, but offered different solutions for creating COM objects for different languages.

How do you create a component in .NET? In the server application, you define a public class, using the syntax of the preferred .NET language. In the client, you import a reference to the component application and then create an instance of the component class. That is it. You can then use the component. The arcane syntax of COM is gone.

The developer controls the lifetime of a COM object. AddRef and Release live in infamy. They are methods of the IUnknown interface and control the persistence of the COM object. If implemented incorrectly, a COM object could be released prematurely or, conversely, never be released and be the source of memory leaks. The .NET memory manager, appropriately named the Garbage Collector, is responsible for managing component lifetimes for the application—no more AddRef and Release.

COM was largely a Windows standard, and building bridges to components in other platforms was difficult. COM was still a worthwhile endeavor and did indeed advance the concept of component development. However, now the torch has been handed to .NET. Using open standards, .NET components are potentially accessible to everyone at anytime.

Component versioning was a considerable problem with COM and contributed to DLL Hell. Another contributor was COM’s reliance on the Windows Registry. Let us assume that two versions of the same in-process server (COM DLL) are installed on the same computer, and the newer version is installed first. The older version will override the Registry settings of the newer component, and clients will be redirected to the incorrect version. Clients using newer services will immediately break. .NET does not rely on the Registry for component registration, which diminishes the possibility of DLL Hell.

I have been teaching .NET to developers for some time and usually start class with a question for my students: Can someone describe the benefits of .NET for end users? Students quickly mention the common language runtime, ASP.NET, XML integration, Garbage Collection, and so on. They are all great things, but they benefit programmers rather than end users. Why would clients give a whit about .NET? The benefit of .NET to users is the new generation of software that .NET introduces: software that runs anywhere, at anytime, on any platform, and from devices large and small.

.NET Framework Architecture

.NET is tiered, modular, and hierarchal. Each tier of the .NET Framework is a layer of abstraction. .NET languages are the top tier and the most abstracted level. The common language runtime is the bottom tier, the least abstracted, and closest to the native environment. This is important since the common language runtime works closely with the operating environment to manage .NET applications. The .NET Framework is partitioned into modules, each with its own distinct responsibility. Finally, since higher tiers request services only from the lower tiers, .NET is hierarchal. The architectural layout of the .NET Framework is illustrated in Figure 1.1.

Figure 1.1 An overview of the .NET architecture.

.NET Framework is a managed environment. The common language runtime monitors the execution of .NET applications and provides essential services. It manages memory, handles exceptions, ensures that applications are well-behaved, and much more.

Language interoperability is one goal of .NET. .NET languages share a common runtime (the common language runtime, a common class library), the Framework Class Library (FCL), a common component model, and common types. In .NET, the programming language is a lifestyle choice. Except for subtle differences, C#, VB.NET, or JScript.NET offer a similar experience.

.NET abstracts lower-level services, while retaining most of their flexibility. This is important to C-based programmers, who shudder at the limitations presented in Visual Basic 6 and earlier.

Let us examine each tier of the .NET Framework as it relates to a managed environment, language interoperability, and abstraction of lower-level services.

Managed Languages and Common Language Specification

.NET supports managed and unmanaged programming languages. Applications created from managed languages, such as C# and VB.NET, execute under the management of a common runtime, called the common language runtime.

There are several differences between a compiled managed application and an unmanaged program.

  • Managed applications compile to Microsoft Intermediate Language (MSIL) and metadata. MSIL is a low-level language that all managed languages compile to instead of native binary. Using just-in-time compilation, at code execution, MSIL is converted into binary optimized both to the environment and the hardware. Since all managed languages ultimately become MSIL, there is a high degree of language interoperability in .NET.
  • Metadata is data that describes data. In a managed application, also called an assembly, metadata formally defines the types employed by the program.
  • Wave a fond goodbye to the Registry. Managed applications are sweeping away the Registry, Interface Definition Language (IDL) files, and type libraries with a single concept called metadata. Metadata and the related manifest describe the overall assembly and the specific types of an assembly.
  • Managed applications have limited exposure to the unmanaged environment. This might be frustrating to many programmers, particularly experienced C gurus. However, .NET has considerable flexibility. For those determined to use unmanaged code, there are interoperability services.

Note: In .NET, a managed application is called an assembly. An assembly adheres to the traditional Portable Executable (PE) format but contains additional headers and sections specific to .NET. MSIL and metadata are the most important new additions to the .NET PE. When the .NET Framework is installed, a new program loader recognizes and interprets the .NET PE format. In future Windows operating systems, the first being .NET Server, the .NET loader is automatically provided.

What is a managed language? If someone wants to create Forth.NET, are there established guidelines? Common Language Specification (CLS) is a set of specifications or guidelines defining a .NET language. Shared specifications promote language interoperability. For example, CLS defines the common types of managed languages, which is a subset of the Common Type System (CTS). This removes the issue of marshaling, a major impediment when working between two languages.

Common Type System

The Common Type System (CTS) is a catalog of .NET types.System.Int32, System.Decimal, System.Boolean, and so on. Developers are not required to use these types directly. These types are the underlying objects of the specific data types provided in each managed language. The following is the code for declaring an integer in C# and Visual Basic .NET. Either syntax maps to a Sys tem.Int32 object.

int nVar=0;
dim nVar as integer=0

Preferably, you should use the syntax of the language and not the underlying object type, leaving .NET the flexibility to select the most appropriate type and size for the operating environment.

The common type system is a pyramid with System.Object at the apex. .NET types are separated into value and reference types. Value types, which are mainly primitive types, inherit from System.ValueType and then System.Object. Reference types—anything not a value type—are derived from System.Object, either directly or indirectly. Value types are short-term objects and are allocated on the stack. Reference types are essentially pointers and allocated on the managed heap. The lifetime of reference types is controlled by the Garbage Collector.

Note: There are many more differences between a value type and reference types, which is a subject beyond the context of this book.

Value types can be converted to reference types, and vice versa, through processes called boxing and unboxing, respectively. Boxing is helpful when a developer needs to change the memory model of an object.

The contributions of CTS extend well beyond the definitions of common data types. CTS helps with type safeness, enhances language interoperability, aids in segregating application domains, and more. Type verification occurs during just-in-time compilation, ensures that MSIL safely accesses memory, and confirms that there is no attempt to access memory that is not formerly defined in metadata. If so, the code is treated as a rogue application. CTS provides a shared type substratum for .NET, enhancing language interoperability. Finally, .NET introduces lightweight processes called application domains. Application domains are processes within a process. Application domains are more scalable and less expensive then traditional Win32 processes. .NET must police application domains and guarantee that they are good neighbors. Code verification, type safeness, and CTS play a role in guaranteeing that application domains are safe.

.NET Framework Class Library

The .NET Framework Class Library (FCL) is a set of managed classes that provide access to system services. File input/output, sockets, database access, remoting, and XML are just some of the services available in the FCL. Importantly, all the .NET languages rely on the same managed classes for the same services. This is one of the reasons that, once you have learned any .NET language, you have learned 40 percent of every other managed language. The same classes, methods, parameters, and types are used for system services regardless of the language. This is one of the most important contributions of FCL.

Look at the following code that writes to and then reads from a file. Here is the C# version of the program.

static public void Main()
   StreamWriter sw=new StreamWriter("date.txt ",true);
   DateTime dt=DateTime.Now;
   string datestring=dt.ToShortDateString()+" "+
   StreamReader sr=new StreamReader("date.txt ");
   string filetext=sr.ReadToEnd();

Next is the VB.NET version of the program.

shared public sub Main()
   dim sw as StreamWriter=new StreamWriter("date.txt ",true)
   dim dt as DateTime=DateTime.Now
   dim datestring as string=dt.ToShortDateString()+" " __
   dim sr as StreamReader=new StreamReader("date.txt ")
   dim filetext as string=sr.ReadToEnd()
end sub

Both versions of the program are nearly identical. The primary difference is that C# uses semicolons at the end of statements, while VB.NET does not. The syntax and use of StreamReader, StreamWriter, and the Console class are identical: same methods, identical parameters, and consistent results.

FCL includes some 600 managed classes. Aflat hierarchy consisting of hundreds of classes would be difficult to navigate. Microsoft partitioned the managed classes of FCL into separate namespaces based on functionality. For example, classes pertaining to local input/output can be found in the namespace System. IO. To further refine the hierarchy, FCL namespaces are often nested; the tiers of namespaces are delimited with dots. System.Runtime.InteropServices, System.Security.Permissions, and System.Windows.Forms are examples of nested namespaces. The root namespace is System, which provides classes for console input/output, management of application domains, delegates, garbage collection, and more.

Prefixing calls with the namespace can get quite cumbersome. You can avoid needless typing with the using statement, and the namespace is implicit. If two namespaces contain identically named classes, an ambiguity may arise from the using statement. Workarounds for class name ambiguity are provided by defining unique names with the using directive. Here is a simple program written without the using statement.

public class Starter
   static void Main()
      System.Console.WriteLine("Hello,world ");

This the same program with the using statement. Which is simpler? Undeniably, the next program is simpler and more readable.

using System;
using System.Windows.Forms;
public class Starter
   static void Main()
      Console.WriteLine("Hello,world ");

It is hard to avoid the FCL and write a meaningful .NET application. Developers should fight the tendency or inclination to jump to unmanaged code for services provided in .NET. It may appear simpler because you have used that unmanaged API a hundred times. However, your program then becomes less portable, and security issues may arise later. When in Rome, do as the Romans do. When in .NET, use managed code.

More by Author

Must Read