1.3 .NET Framework Design Goals
The Microsoft .NET Framework embodies
design goals that are both practical and ambitious. In this section,
we discuss the main design goals of the Microsoft .NET Framework,
including support for components, language integration, application
interoperation across the Web, simplified development and deployment,
improved reliability, and greater security.
1.3.1 Component Infrastructure
Prior to the introduction of
COM technology, developers had no
standard way to integrate binary libraries without referring to or
altering their source code. With the advent of COM, programmers were
able to integrate binary components into their applications, similar
to the way we can plug-and-play hardware components into our desktop
PCs. Although COM was great, the grungy details of COM gave
developers and administrators many headaches.Although COM permits you to integrate binary components developed
using any language, it does require you to obey the COM identity,
lifetime, and binary layout rules. You must also write the plumbing
code that is required to create a COM component, such as
DllGetClassObject, CoRegisterClassObject, and others.Realizing that these requirements result in frequent rewrites of
similar code, .NET sets out to remove them. In the .NET world, all
classes are ready to be reused at the binary level. You
don't have to write extra plumbing code to support
componentization in the .NET Framework. You simply write a .NET
class, which then becomes a part of an assembly (to be discussed in
Chapter 2) that inherently supports
plug-and-play.In addition to providing a framework to make development easier, .NET
removes the pain of developing COM components. Specifically, .NET
removes the use of the registry for component registration and
eliminates the requirements for extraneous plumbing code found in all
COM components, including code to support IUnknown, class factories,
component lifetime, registration, dynamic binding, and others.
|
1.3.2 Language Integration
COM supports language independence, which means
that you can develop a COM component in any language you want. As
long as your component meets all the rules spelled out in the COM
specification, it can be instantiated and used by your applications.
Although this supports binary reuse, it doesn't
support language
integration. In other words, you can't
reuse the code in the COM components written by someone else; you
can't extend a class hosted in the COM component;
you can't catch exceptions thrown by code in the COM
component; and so forth.Microsoft .NET supports not only language independence, but also
language integration. This means that you can inherit from classes,
catch exceptions, and take advantage of polymorphism across different
languages. The .NET Framework makes this possible with a
specification called the Common Type System (CTS), which all .NET
components must support. For example, everything in .NET is an object
of a specific class that derives from the root class called
System.Object. The CTS supports the
general concepts of classes, interfaces, delegates (which support
callbacks), reference types, and value types. The .NET base classes
provide most of the base system types, such as those that support
integer, string, and file manipulation. Because every language
compiler must meet a minimum set of rules stipulated by
the Common
Language Specification (CLS) and generate code to conform to the CTS,
different .NET languages can be used in the same application. We will
examine the CTS and CLS in Chapter 2.
1.3.3 Internet Interoperation
COM supports distributed computing through
its Distributed COM (DCOM) wire
protocol. A problem with DCOM is that it embeds the host TCP/IP
address inside the Network Data Representation
(NDR) buffer, such that it will not work through firewalls and
Network Address Translation (NAT)
software. In addition, the DCOM dynamic activation, protocol
negotiation, and garbage collection facilities are proprietary,
complex, and expensive. The solution is an open, simple, and
lightweight protocol for distributed computing. The .NET Framework
uses the industry-supported SOAP protocol, which is based on the
widely accepted XML standards.
1.3.4 Simplified Development
If you have developed software for the Windows platforms since their
inception, you have seen everything from the Windows APIs to the
Microsoft Foundation
Classes (MFC), the Active Template Library (ATL), the
system COM interfaces, and countless other environments, such as
Visual Interdev, Visual Basic, JScript, and other scripting
languages. Each time you set out to develop something in a different
compiler, you had to learn a new API or a class library, because
there is no consistency or commonality among these different
libraries or interfaces..NET solves this problem by providing a set of framework classes that
every language uses. Such a framework removes the need for learning a
new API each time you switch languages.
1.3.5 Simplified Deployment
Imagine this scenario: your Windows
application, which uses three shared Dynamic Link Libraries (DLLs),
works just fine for months, but stops working one day after
you've installed another software package that
overwrites the first DLL, does nothing to the second DLL, and adds an
additional copy of the third DLL into a different directory. If you
have ever encountered such a brutalyet entirely
possibleproblem, you have entered DLL Hell. And if you ask a
group of seasoned developers whether they have experienced DLL Hell,
they will grimace at you in disgust, not because of the question
you've posed, but because they have indeed
experienced the pain and suffering.To avoid DLL Hell on Windows 2000 and subsequent Windows operating
systems (at least for system DLLs), Windows 2000 stores system DLLs in a
cache. If you install an application that overwrites system DLLs,
Windows 2000 will overwrite the added system DLLs with the original
versions from the cache.Microsoft .NET further diminishes DLL Hell. In the .NET environment,
your executable will use the shared DLL with which it was built. This
is guaranteed, because a shared DLL must be registered against
something similar to the Windows 2000 cache, called
the Global Assembly Cache (GAC).
In addition to this requirement, a shared DLL must have a unique hash
value, public key, locale, and version number. Once
you've met these requirements and registered your
shared DLL in the GAC, its physical filename is no longer important.
In other words, if you have two versions of a DLL that are both
called
MyDll.dll,
both of them can live and execute on the same system without causing
DLL Hell. This is possible because the executable that uses one of
these DLLs is tightly bound to a specific version of the DLL during
compilation.In addition to eradicating DLL Hell, .NET also removes the need for
component-related registry settings. A COM developer will tell you
that half the challenge of learning COM is understanding the
COM-specific registry entries for which the developer is responsible.
Microsoft .NET stores all references and dependencies of .NET
assemblies within a special section called a
manifest
(see Chapter 2). In addition, assemblies can be
either private or shared. Private assemblies are found using logical
paths or XML-based application configuration files, and public
assemblies are registered in the GAC; in both cases, the system will
find your dependencies at runtime. If they are missing, you get an
exception telling you exactly what happened.Finally, .NET brings back the concept of zero-impact installation and
removal. This concept is the opposite of what you have to deal with
in the world of COM. To set up a COM application, you have to
register all your components after you have copied them over to your
machine. If you fail to perform this step correctly, nothing will
work and you'll end up pulling your hair out.
Likewise, to uninstall the application, you should unregister your
components (to remove the registry entries) prior to deleting your
files. Again, if you fail to perform this step correctly, you will
leave remnants in the registry that will be forever extant.Unlike COM, but like DOS, to set up an application in .NET, you
simply xcopy your files from one directory on a CD
to another directory on your machine, and the application will run
automatically.[1] Similarly, you can just delete the
directory to uninstall the application from your machine.[1] This is true for private assemblies,
but not for shared assemblies. See Chapter 4 for more
details.
1.3.6 Reliability
There are many programming languages and
platforms in the commercial software industry, but few of them
attempt to provide both a reliable language and a robust runtime or
infrastructure. The most successful language that we have seen in the
commercial software industry is the Java™ language
and the Java Virtual Machine™, which have brought
the software-development community much satisfaction. Microsoft is
positioning .NET as the next big thing.Microsoft .NET requires type safety. Unlike C++, every class in .NET
is derived from the mother of all classes, Object, which supports
basic features such as returning a string representation of the
object, indicating whether the object is equal to another, and so on.
The CLR must recognize and verify types before they can be loaded and
executed. This decreases the chances for rudimentary programming
errors and prevents buffer overruns, which can be a security
weakness.Traditional programming languages don't provide a
common error-handling mechanism. C++ and Java
support exception handling, but many others leave you in the dust,
forcing to invent your own error-handling facilities. Microsoft .NET
supports exceptions in the CLR, providing a consistent error-handling
mechanism. Put another way: exceptions work across all
.NET-compatible languages.When you program in C++, you must deallocate all heap-based objects
that you have previously allocated. If you fail to do this, the
allocated resources on your system will never be reclaimed even
though they are no longer needed. And if this is a server
application, it won't be robust because the
accumulation of unused resources in memory will eventually bring down
the system. Similar to Java, the .NET runtime tracks and
garbage-collects all allocated objects
that are no longer needed.
1.3.7 Security
When developing
applications in the old days of DOS, Microsoft developers cared
little about security because their applications ran on a single
desktop with a single thread of execution. As soon as developers
started developing client and server applications, things got a bit
complicated: multiple users might then have accessed the servers, and
sensitive data might be exchanged between the client and the server.
The problem became even more complex in the web environment, since
you could unknowingly download and execute malicious applets on your
machine.To mitigate these problems, .NET provides a number of security
features. Windows NT and
Windows 2000 protect resources
using access-control lists and security identities, but
don't provide a security infrastructure to verify
access to parts of an executable's code. Unlike
traditional security support in which only access to the executable
is protected, .NET goes further to protect access to specific parts
of the executable codethis is known as code access
security. For example, to take advantage of declarative
security checks, you can prefix your method implementations with
security attributes without having to write any code. To take
advantage of imperative security checks, you write the code in your
method to explicitly cause a security check. .NET provides other
security features to make it harder to penetrate your applications
and system.