- Introduction
- .NET ORPC Options
- Enabling .NET Remoting Protocols
- When to Use Which Protocol
- .NET Remoting Protocols Comparison
- Conclusion
.NET Remoting Protocols Comparison
We're now ready to delve into the subject from a technical point of view. The following sections provide an analytic comparison of .NET Remoting protocols in different areas. This analysis applies to the .NET Framework version 1.1.
Firewall Friendliness and Interoperability
A firewall-friendly protocol requires very few ad hoc ports to be opened in order to work properly (a real firewall-friendly one requires no custom ports at all). Firewall-unfriendly protocols are rarely used across the Internet because their deployment is strongly discouraged by network administrators, who consider every port opened to the Internet as a potential breach into their LAN (and they're right).
The term interoperability indicates to what degree (if any) a protocol is available from different vendors on different operating systems.
DCOM
DCOM is a Microsoft proprietary technology that requires port 135 for the initial communication handshake, plus an additional range of ports whose numbers depend on the number of running processes hosting DCOM objects (this includes MTS/COM+ server applications). The default port range is huge, but it can generally be reduced to about 1020; this requires testing and depends on the number of DCOM servers running on the server computer. With Windows 2000 Service Pack 3 or later, you can assign a specific port to a specific COM+ application, which lets you fine-tune the number of ports you need to open into your firewalls.
A couple of additional issues to be aware of: DCOM cannot work across Network Address Translation (NAT), and callbacks are not carried on the same port (but a new one is open). The latter statement means that when a callback is set up, the client and server roles are reversed so that the firewall sees the server as a client trying to open a network communication to the outsideand this will likely fail in a default firewall configuration.
DCOM is not natively firewall-friendly, but most times you can make it work, with some effort. Firewall-tuning requirements are not actually the reason why DCOM never made it as an Internet protocol, though. The problem lies in the fact that DCOM is too chatty and connection-oriented for low-bandwidth/unreliable network connections like the Internet. (By the way, the same statement applies to CORBA and RMI.)
.NET Remoting
With .NET Remoting, you're responsible for providing a hosting process where .NET classes are loaded and exposed for remote accessbut you can use Internet Information Services (IIS) as the hosting process. Each server process can define the TCP/HTTP channels to be opened via a configuration file; you don't have to modify any registry key. A single channel can be used to make reachable as many components as you like within the same process. This makes configuring .NET Remoting much easier than configuring DCOM.
Unfortunately, .NET Remoting handles callbacks just as DCOM does. This is a problem in the presence of firewalls and NAT. Thanks to the extensibility provided by .NET Remoting, however, there are third-party products (such as Genuine Channels) that reuse the connection opened by the server for callbacks. You might want to give them a try.
Web Services
One of the main goals of SOAP was developing an Internet-friendly protocol. This goal was easily achieved, as SOAP uses HTTP as its preferred transport protocol. You'll hardly find a firewall blocking incoming HTTP traffic on port 80. Additionally, the SOAP payload is expressed in terms of XML. Because XML is an industry standard, you can find an XML parser on any operating system. HTTP and XML are therefore the right couple to make web services the Internet-friendly, interoperable protocol of the future. What about callbacks and issues like that? Easy answer: In SOAP, all objects are marshaled by value, so no callbacks are possible. <g>
Security
Security is the number one issue when it comes to moving your data across the wire. The term security encompasses basically two aspects:
Mutual authentication and authorization: who are you and what can you do
Data encryption and integrity: Data must be encrypted to be protected from unauthorized sniffing and tampering
DCOM
DCOM supports a full-fledged security model based on the Windows security infrastructure, but DCOM security is tricky to configure if the default settings don't suit your needs. However, once it's set up correctly, DCOM security is a very solid infrastructure. It allows authentication, impersonation (which makes this model more flexible but more complex to manage), data integrity, and privacy. COM+ adds an additional application-level security mechanism: role-based security (not to be confused with .NET role-based security). You can define roles within a COM+ application and add Windows users to roles. Then it's possible to allow or block access to certain functionalities of your applications programmatically or declaratively, according to the role to which the remote caller's identity is mapped.
.NET Remoting
.NET Remoting has no built-in security mechanism (this is its greatest weakness). You have three options here: roll your own, get a third-party implementation, or use IIS as the hosting process. There are some unsupported samples around. The most significant one I'm aware of is a Microsoft unsupported package you can download.
In real-world applications, the only viable solution is opting for IIS hosting. In this way you get HTTPS support for free. There is one drawback: You can only use the HTTP channel. Unfortunately, this puts the fastest .NET Remoting configuration out of the picture (binary formatter over TCP). HTTPS guarantees privacy integrity and server authentication. You get client authentication and therefore client authorization using any of the mechanisms provided by IIS (basic, digest, Windows).
Web Services
As I said earlier, SOAP specs don't address security issues. You can get security support for web services by exposing them via an HTTPS endpoint exactly as described for .NET Remoting. In some scenarios, HTTPS and IIS authentication mechanisms are far from being flexible and interoperable enough in real Internet-distributed applications. Microsoft and IBM are aware that the absence of a solid and interoperable security infrastructure for web services is the main reason that keeps the IT community from using web services heavily. That's why the two giants, under the umbrella of the WS-I consortium, are developing specs that address the main features currently lacking in the web services infrastructure: security, federation, distributed transactions, routing, etc. The security-related part of these specs is called WS-Security. Microsoft provides the Web Services Enhancements (WSE) package, which extends web services support in the .NET runtime, adding concrete implementation to some of these specs.
TIP
The MSDN article "Programming with Web Services Enhancements 2.0" provides a good starting point to get deeper into WSE-related technologies.
WSE is a supported piece of software, but because the specs are far from being officially ratified and agreed upon by major software vendors, the API exposed by WSE will certainly change in future releases (as clearly stated by Microsoft's web services architect, Don Box, in a recent Tech Ed session).
Performance
With regard to raw performance, DCOM is the fastest protocol available, but .NET Remoting is very close when configured to use the binary formatter over the TCP channel (but remember that this option is not available when hosting .NET Remoting components in IIS). You obviously lose performance when using the SOAP formatter and/or the HTTP channel. Web services performances fall in the middle between the fastest .NET Remoting configuration (TCP-Binary) and the slowest (HTTP-SOAP). You might expect web services performance to be comparable with the slowest .NET Remoting option (web services use the XML formatter over HTTP, which appears very similar to .NET Remoting using the SOAP formatter over HTTP). This isn't the case, however, because the XML formatter is more efficient and lightweight than the .NET Remoting SOAP formatter. This sounds reasonable because the XML formatter is the less powerful of the two. Some detailed test results are available.
Customization and Extensibility
An important aspect to analyze is to what degree an ORPC supports customization and extensibility.
Customization indicates how much you can tune and modify the default protocol behavior. This is crucial, for instance, in unusual network configurations on which the protocol must be used.
The term extensibility refers to how much and how easily you can plug your own hooks into the protocol stack to add extra functionalities into it.
DCOM
DCOM supports very few customization and extensibility options. It's basically a black box. You can configure some aspects via some registry settings or API calls, but there are very few hooks into its stack accessible by C++ gurus and none at all by mere mortals.
.NET Remoting
.NET Remoting can be highly customized using configuration files, and supports a complete extensibility model (Custom Proxy and Custom Sinks) that lets you drop your own piece of software into the .NET Remoting pipeline. You can access and modify messages that the two remote-communication endpoints send each other. Implementing data compression or a custom object-pooling mechanism (just as a couple of examples) are feasible tasks for a programmer with average skills.
Web Services
Web services offer a large degree of customization and extensibility. Web services expose two different kinds of hooks to their remote stack: SOAP Extensions and HTTP modules. The former are specific to web services, while the latter are part of the ASP.NET module, which is used by .NET to dispatch calls to web services. SOAP Extensions are similar to .NET Remoting sinks. They let you insert your piece of software into the call stack to add logging, XML schema validation, or whatever you need. Additional extensibility features are being added by WSE as WS-Routing and WS-Referral.
Remote Invocation Semantics
Regardless of the invocation transparency in the activation process, in most cases a remote object doesn't behave as a local one, period. There are two main points that must be fully understood before you can use a specific protocol effectively: the remote object's lifetime and the way parameters are passed to method calls. The second one especially is often poorly understood by programmers. Let's see what the three .NET protocols offer in this regard.
DCOM
DCOM provides a standard activation model that makes the remote object appear indistinguishable from a local one. In DCOM, a remote object stays alive as long the client has a reference to it. COM+ services added the possibility of flagging components hosted in a COM+ application as just-in-time activated, and each of its methods as autocomplete. With such an attributes combination in place, the object is transparently destroyed after each method call and a new one is created when the next client call arrives.
In COM, unless an object implements the IMarshal interface (really not for the faint of heart), all objects placed as parameters of a remote call are passed by reference; in real life, the only example of marshal-by-reference objects is disconnected ADO Recordsets. In the .NET world, when you pass a .NET object as a parameter of a DCOM-based call, the behavior may vary. If the object inherits from MarshalByRef, it's transported by reference; that is, the object doesn't move from the process where it was created and the callee just receives a pointer to it. If the object is marked with the Serializable attribute, on the other hand, it's transported by value; that is, a new instance of the same class is created in the callee process and the original object's state is copied into the new one. If neither of the two applies, the call fails.
.NET Remoting
.NET Remoting offers three activation mechanisms:
A standard mechanism similar to DCOM (such objects are client-activated, in .NET Remoting terminology)
Single call
Singleton
Single call objects are destroyed after each method call. When a class is configured to run as a Singleton, there is only one instance bound to any activation request serving all client callsso watch out for proper synchronization!. You can choose the object behavior via configuration files, without the need to recompile. However, the activation mode can't be an afterthought; you program your classes with an activation model in mind. In a real-life scenario, you can't switch from one to another without modifying code structure.
The behavior of objects that are parameters of a .NET Remoting call is identical to that described in the DCOM section.
You can choose between two different formatters (which determine the data format of the payload transmitted over the wire): the SOAP formatter or the Binary formatter. Both have been written to be .NET-centric, so that they can transport and reconstitute on the other side of the network objectsgraphs with full fidelity. As we will see, this doesn't hold when putting objects into a web services method call.
Web Services
Web services can hardly be defined as ORPC when it comes to describing supported call semantics. To get the picture, think of web services as sending email messages in a structured way. <g> There's no support for callbacks, since there's no support for marshaling by reference objects. I want to stress that this is not a fault of web services; this definitely makes sense if you're using web services in the proper context.
All objects put into a web services call are passed by value using the XML formatter. The XML formatter is XML Schemacentric (XML Schema is a W3C standard) to guarantee full interoperability with other vendors and/or platforms. There are some possible variations on how SOAP messages as a whole and each method call parameter are formatted in a SOAP message. This is basically due to the fact that the first SOAP specifications were released before the release of XML Schema specifications. You basically have two options: using the Document/Literal style or the Encoded/RPC style. The former is the default, but you can control such settings by applying the proper attributes to methods and classes. Document/Literal is the recommended option, since it relies completely on XML Schema to describe the message payload. As a consequence, it guarantees the greatest compatibility among software vendors and platforms.
CAUTION
XML schema specs have no knowledge of entity references; neither does the XML formatter. This means that if you pass a graph of objects with circular reference, the XML formatters will blow up with a serialization error. The classic example of circular reference is object A holding a reference to object B, which in turns holds a reference to object A. Think about how many times you've handled such an object graph. Quite often, I guess, so watch out.
Deployment, Decoupling Issues, Location Transparency
Last but not least, deployment, decoupling issues, and location transparency are important points to take into account. Deployment and decoupling issues are related and strongly affect how quickly you can build a robust setup for your application and the number of maintenance/upgrade problems you'll face during the application lifetime.
DCOM
DCOM protocol is enabled for inter-machine communication when serviced components are deployed in server applications. COM+ provides a great one-click functionality that produces a proxy export (in the form of an .MSI file) from a COM+ server application. Just run it on the client machine and you're ready to go. The MSI package copies and registers all required type libraries; .NET assemblies on the client machine also puts required entries in the registry. Strictly speaking, DCOM doesn't require the .NET assembly to be installed on the client; all it needs are registered type libraries for marshaling and proper registry entries. However, .NET clients need to load the types they refer to, and that's why .NET assemblies are deployed on the client as well.
DCOM provides complete location transparency. This is great to simplify your code, but remember not to overuse location transparency; you must design object interfaces knowing if they'll be called locally or remotely.
.NET Remoting
.NET Remoting requires the developer to provide a host process where remote activated objects run. You typically host the components in a Windows Server .EXE or configure the IIS process to host the components (if you can afford the performance penalties). In any case, the maintenance and setup hurdles are greater than in COM+. The server process must be instructed via configuration files or programmatically about which classes must be exposed to remote access and what network ports must be opened. Only server-activated objects let you decouple interface from implementation so that only assemblies containing interfaces need to be deployed on the client. Unfortunately, client-activated objects require the concrete class types to be available on the client as well (though not necessarily referenced by the client program). A tool named Soapsuds lets you get a "type definition only" assembly out of a "concrete assembly," but this tool is somewhat buggy and imposes additional maintenance and setup hurdles.
.NET Remoting offers less location transparency than DCOM does. The best you can get is defining the proper configuration file and having the client load it on the Main startup routine. After that, you can use the standard new constructor to create and gain access to the object running on the remote machine.
Web Services
Web services invocation is made transparent by proxy classes that hide the calling program from the details of the SOAP protocol. The caller interacts with these proxy classes running locally on the client machine; nothing reveals on the client code that a remote call is taking place. Such proxy classes are created automatically by Visual Studio .NET when you add a "web reference" to your client project. A proxy class is added to the client project and compiled into it so that you don't need to deploy additional assemblies on the client side.