Using .NET Remoting to Meet the Challenges
Ultimately, it’s all about money. An organization can make more money if it can create better solutions faster and without having to fret over finding enough superstar developers who can juggle all the disparate complex technologies needed to develop large-scale, real-world solutions. Although DCOM is well-equipped to solve complex distributed application problems, it requires significant expertise. You can’t always solve these sorts of problems with wizards and naïve development concepts, but you can do a lot to simplify and consolidate the configuration, programming model, and extensibility of DCOM. This is .NET Remoting’s greatest strength. .NET Remoting greatly simplifies—or better yet, organizes—the approach to creating and extending distributed applications. This level of organization makes developers more productive, systems more maintainable, and possibly, organizations a bit richer.
If you configure a .NET Remoting application for optimal performance, the speed will be comparable to that of DCOM, which is very fast. Of course, when configured this way, .NET Remoting applications have the same interoperability constraints as the DCOM applications they’re comparable with. Fortunately, configuring .NET Remoting applications for maximum performance versus interoperability is as easy as specifying a couple of entries in a configuration file.
.NET Remoting performance differs from DCOM performance when the client and server are on the same machine. The DCOM/COM infrastructure detects that the processes are local and falls back to a pure COM (more optimized communication) method. .NET Remoting will still use the network protocol that it was configured to use (such as TCP) when communicating among application domains on the same machine.
Extending and Customizing Remoting
Making a system easy to use for simple, common scenarios yet logically extensible and customizable for more advanced ones is a universal software design problem. How well .NET Remoting solves this problem is probably the technology’s strongest feature. For the common cases, .NET Remoting supports many distributed scenarios with little work or configuration through its pluggable architecture. Therefore, it’s easy to get a distributed application running. You might say that pluggability is the next layer above component development. Component development provides greater encapsulation of objects into building blocks that can be assembled into working applications. In a similar vein, pluggable architectures support swapping entire subsystems of functionality as long as they support the same “plug.” For example, the .NET Remoting architecture supports plugging in the type of channel you want (such as HTTP or TCP) and the type of formatter you want (such as binary or SOAP). This way, you can make common yet powerful configuration choices based on performance and interoperability, simply by plugging in a new module.
.NET currently supports configuring remoting applications in three ways:
- Using configuration files
Remoting can be easily configured by using XML-based files. Using an open standard such as XML for configuration data is a big improvement over using the Windows registry. For example, various instances of remoting applications can coexist on the same machine and be separately configured via configuration files located in their own private directories. Configuration files also facilitate what’s known as Xcopy deployment for .NET Remoting applications. Xcopy deployment is a method of deploying applications by simply copying a directory tree to a target machine instead of writing setup programs and requiring the user to run them to configure applications. After the initial installation, maintenance is far easier because reconfiguring the application is as easy as copying a new configuration file into the same directory as the remote application’s executable. This ease of configuration simply isn’t possible when using the registry-based configuration of COM objects.
Configuration files come in three flavors, based on their scope:
Used for machinewide settings
Used to configure ASP.NET applications and .NET Remote objects hosted under Microsoft Internet Information Server (IIS)
- Application configuration file
Used to configure a specific application domain
Developers who don’t want to allow changes to remoting configuration can retain full control over the settings within code.
- Using the .NET Framework Microsoft Management Console (MMC) snap-in
Although programmatic and file-based configuration is considered the domain of the developer, MMC snap-in configuration is supplied to allow the administrator to configure remoting applications. Although this GUI-based configuration tool doesn’t give you the control that code and configuration files provide, its scope is directed at the tasks an administrator would want to perform.
CLR and CTS Benefits
A distributed object technology derives a lot of its power and ease of use from its underlying type system and object model. DCOM is subject to the same limitations of COM’s type system and object-oriented feature constraints. With COM, there’s no implementation inheritance except through constructs such as aggregation and containment. Error handling is limited to return codes because COM doesn’t support exceptions. COM’s type system is also inconsistent and disparate. C++ COM systems use source code type descriptions (IDL), while Visual Basic and scripting languages rely on binary type representations (type libraries). Neither IDL nor type libraries are a definitive standard because both support constructs that aren’t supported by the other. Finally, COM doesn’t support a number of object-oriented features, such as static modifiers, virtual functions, and overloaded methods.
By contrast, .NET Remoting is easy to use and powerful, largely because it’s based on the common type system (CTS) and the common language runtime (CLR). Type information, known as metadata, is consistent and accessible. The .NET Framework CTS defines the basic types that all .NET-compliant languages must support. These types are the atoms that all remoting clients and servers can count on for compatible communication with the same fidelity as classes communicating within a single project. Furthermore, this metadata is unified and stored within the defining assembly so that remote objects don’t need separate type descriptions such as DCOM and CORBA.
Because .NET Remoting can use the full power of .NET’s object-oriented features, it supports full implementation inheritance; properties; and static, virtual, and overloaded methods. The CLR and CTS allow developers to use a single object system for both local and remote objects and to avoid implementing designs in which the distribution of objects limits object-oriented programming choices. Finally, .NET fully supports exception propagation across remoting boundaries, meaning that handling errors in distributed objects is a big improvement over DCOM’s return code error handling.
Customer demand for enterprise technologies such as distributed object technologies has changed during the past few years. For a technology to succeed today, it needs to balance power and ease of use in closed systems as well as possess an ability to interoperate with other potentially proprietary and legacy systems. This is one of .NET Remoting’s key design goals. .NET Remoting meets the interoperability goal by supporting open standards such as HTTP, SOAP, Web Service Description Language (WSDL), and XML. To pass through firewalls, you can plug in an HTTP channel. (We’ll discuss channels in Chapter 7, “Channels and Channel Sinks.”) To communicate with non-.NET clients and servers, a developer can plug in a SOAP formatter. (We’ll discuss formatters in Chapter 8, “Serialization Formatters.”) Remoting objects can be exposed as Web Services, as we’ll discuss in Chapter 3. The .NET Remoting Framework and IIS lets you generate Web Service descriptions that you can provide to developers of non-.NET clients so that they can interoperate over the Internet with the .NET remote objects.
In Figure 1-4, you’ll see two common .NET Remoting scenarios: an HTTP channel/SOAP formatter configuration for maximum interoperability, and a higher-performing TCP channel/binary formatter configuration. Both configurations can be set by plugging in simple options.
The security model for .NET Remoting systems has changed quite a bit from the complex and highly configurable model of DCOM. For the initial release of the .NET Framework, the best way to implement a secure remoting system is to host the remote server inside IIS. The best part of hosting inside IIS is that you can use its strong security features without changing the client’s code or the server’s code. This means you can secure a remoting system just by changing the hosting environment to IIS and passing credentials (user name, password, and optionally, the domain) by setting a client configuration option. We’ll give an example of IIS hosting in Chapter 3, but for now we’ll look at some of the security options IIS provides.
Figure 1-4. Interoperability vs. performance
IIS has rich support for various authentication mechanisms, including Windows Integrated Security (NTLM), Basic authentication, Passport authentication, and certificate-based services. NTLM provides the same robust security system as Windows NT and its successors. This is an ideal choice for intranet applications because NTLM doesn’t support authentication over firewalls and proxy servers. However, for Internet-based remoting and other authentication scenarios involving firewalls, you’ll need a scheme such as Basic or Passport authentication.
After the user is authenticated, your next concern might be to hide sensitive data that’s being marshaled between remoting tiers. IIS also provides a strong solution for encryption: Secure Sockets Layer (SSL). SSL is an industry standard for encrypting data, and IIS fully supports SSL by using server-side certificates. .NET Remoting clients then need only specify https (instead of http) as the protocol in the server’s URL.
Security with Other Hosts
The initial .NET Framework release doesn’t support out-of-the-box remoting security by using hosts other than IIS. However, because the architecture is pluggable, you can write your own custom security solution and plug it in. Writing such a module is beyond the scope of this book. However, there will doubtlessly be many solutions available through the .NET community.
.NET Remoting’s solution to object lifetime management is a prime example of the easy to use in simple cases, logical to extend for complex ones philosophy. First, reference counting and pinging are out. Lease-based lifetimes and sponsors are in. Although DCOM’s reference-counting model is simple in concept, it can be complex, error prone, and poorly configurable in practice. .NET leases and sponsors are easy to use, and they customize both clients and servers and allow them to participate in server lifetime management if desired. As with other .NET Remoting parameters, you can configure object lifetimes both programmatically and via configuration files. (We’ll look at lifetime management in detail in Chapter 2, “Understanding the .NET Remoting Architecture.”)
Enterprise services are like medicine: If you don’t need them, you should avoid them. But if you need them, you really need them. If you do need enterprise services such as distributed transactions, object pooling, and security services, the initial version of the .NET Framework can leverage the robust COM+ services.
When both client and server are running under the CLR, accessing COM+ services is as easy as deriving an object from System.EnterpriseServices.ServicedComponent. Because ServicedComponent ultimately derives from MarshalByRefObject (the type all .NET remote objects derive from), all .NET COM+ objects are automatically remotable. Any object derived from ServicedComponent can use COM+ services by adding attributes to its class or its methods. Attribute programming is a powerful paradigm that, among other things, allows a developer to describe code so that tools and other code can learn about his or her intentions and requirements. For example, a .NET remote object can participate in a transaction by simply applying an attribute to a remote object hosted by COM+.
.NET remote objects can participate in COM+ services and can service both .NET Remoting clients and traditional COM clients. However, to support legacy COM clients, the .NET objects hosted by COM+ use COM for the communication method rather than .NET Remoting. In addition, these .NET objects must be given strong names and registered as traditional COM objects by using the Regasm tool.