Concept of Application Domains
Application Domain, or simple AppDomains are logical subdivisions/partitions within a given process which host a set of .NET related assemblies. A single OS process may host more than one AppDomain. The division of a traditional OS process to AppDomains offers several benefits like:
- AppDomains are far less expensive in terms of processing power and memory that is used for a full-blown process.
- AppDomains provide a deeper level of isolation for hosting a loaded application. If one AppDomain fails the remaining AppDomains remain functional.
Though the AppDomains are being hosted inside the same process, because they are isolated from one another the applications running within different AppDomains can never share any information of any kind. To make the AppDomains interact with each other we have to make use of the .NET Remoting protocol which marshals the data that can be sent from one AppDomain to another AppDomain.
Defining .NET Remoting
.NET Remoting is an enabler for application communication. It is a generic system different applications use to communicate with one another. .NET objects are exposed to remote processes, thus allowing inter-process communication. The applications can be located on the same computer, different computers on the same network, or even computers across separate networks. .NET Remoting is nothing more than the act of two pieces of software communicating across application domains. The two application domains in question could be physically configured in any of the following manners:
- Two AppDomains in the same process.
- Two AppDomains in separate processes in the same machine.
- Two AppDomains in separate processes on different machines.
Regardless of the distance between two software entities, it is common to refer to each agent using the client and server. The client is a piece of software which attempts to interact with a Remote Object. The server is the software agent that provides remote access to select objects.
The .NET Remoting Namespaces
System.Runtime.Remoting
System.Runtime.Remoting.Channels
System.Runtime.Remoting.Channels.Http
System.Runtime.Remoting.Channels.Tcp
System.Runtime.Remoting.Mesaging
Understanding the Remoting Framework
When clients and servers exchange information across application boundaries, the CLR makes use of several low level primitives to ensure the entities in question are able to communicate with each other as transparently as possible. As a .NET programmer we are not going to write the networking code to invoke methods on the remote object. Similarly, the server process is not required to pick the packets from the network by itself and reformat them to understand the contents. The CLR takes care of such details automatically.
Basically the .NET Remoting Layer revolves around a careful orchestration that takes place between four key players:
- Proxies
- Messages
- Channels
- Formatters
Proxies
Client and server do not communicate via a direct connection, but rather they use a middleman termed Proxy. The proxy is used to fool the client into believing that it is communicating with a local object in the same AppDomain. To make this possible, a proxy has the identical interface (i.e. members, fields, properties, etc.) as the remote object represents. As far as the client is concerned the given proxy is the remote object and can be operated on as if it were a true local entity. Actually the proxy forwards the calls to the remote type.
The proxy who is invoked directly by the client is termed as the transparent proxy. This CLR auto-generated entity is in charge of ensuring that the client has provided the current no. and type of parameters to invoke the remote method. Assuming that the transparent proxy is able to verify the incoming arguments, this information is packaged up into another CLR generated type termed the Message object.
The message object implements the IMessage
interface and it has a single property (named Properties) that provides access to a collection used to hold the client-supplied arguments. Once the message object is populated by the CLR, it is then passed into a closely-related type termed as Real Proxy. The Real Proxy is the entity that literally passes the message object into the channel (objects responsible for transporting the message to the remote object). Unless and until we are interested in building custom implementation of the client-side real proxy, the only member of interest is RealProxy.Invoke()
. The CLR generated transparent proxy passes the formatted message object into the RealProxy type via its Invoke()
method.
Understanding Channels
Once the proxies have validated and formatted the client supplied arguments into a message object, this IMessage
compatible type is passed from the real proxy into a channel object. The channels are responsible for transporting a message to the remote object, and if necessary ensure that any method return values are passed from the remote object to the client. The .NET class libraries provide two types of channel implementations:
- The TCP Channel.
- The HTTP Channel.
The TCP Channel is represented by the TcpChannel
class type, and is used to pass messages using the TCP/IP network protocol. TcpChannel
is helpful in that the formatted packets are quite lightweight, given that the messages are converted into a tight binary format using a related binary formatter. The result is that use of the TcpChannel
type tends to result in faster remote access. On the downside, TCP channels are not firewall friendly.
The HTTP Channels are represented by the HttpChannel
class type, which converts message objects into a SOAP format using a related SOAP formatter. As we know, SOAP is XML based and it is slightly slower than the TcpChannel
. But in contrast it is firewall friendly given that most firewalls allow texual packets to be passed over port 80.
Regardless of which of these channels we use for transportation, they implement the interfaces like; IChannel
, IChannelSender
, IChannelReceiver
. To allow client and server applications to register their channel of choice, you will make use of the ChannelServices.RegisterChannel()
method, which takes a type implementing IChannel
.
HttpChannel c=new HttpChannel(2625);
ChannelServices.Register(c);
Understanding Formatters
A given channel uses a specific formatter, whose job is to translate the message object into protocol specific terms. So we have to use the BinaryFormatter
or the SoapFormatter
as the case may be.
Once the formatted message is generated, it is passed into the channel, where it will eventually reach its destination application domain, at which time the message is formatted from protocol-specific terms back to .NET-specific terms. At this point an entity named Dispatcher
invokes the correct method on the remote object.
Create a Remotable Object
A remotable object is nothing more than an object that inherits from MarshalByRefObject
. The following sample demonstrates a simple class to expose the omnipresent hello world. This object exposes a single method HelloWorld
that will return a string. The only values that can be returned from methods are the classes in the .NET Framework that are serializable such as string and DataSet
. In addition, if you need to return a user-defined object then the object needs to be marked as serializable.
Create a new C# class library project. Add a class called MyObject
and put in the following code. Add a reference to System.Runtime.Remoting
in the project, otherwise the TcpChannel
will not be found. Compile the class to make sure you have everything correct.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace MyRemoting
{
public class MyObject : MarshalByRefObject
{
public SampleObject()
{
}
public string HelloWorld()
{
return "Hello World!";
}
}
}
Create a Server To Expose the Remotable Object
We need to create a server object that will act as a listener to accept remote object requests. For this example we will use the TCP/IP channel. We first create an instance of the channel and then register it for use by clients at a specific port. The service can be registered as WellKnownObjectMode.SingleCall
, which results in a new instance of the object for each client, or as WellKnownObjectMode.Singleton
, which results in one instance of the object used for all clients.
It is not necessary to create the server listener if you are planning to use IIS. For obvious reasons, IIS only supports the use of the HttpChannel
. Create a virtual directory for your application and then put code to register your service in the Application_Start
event.
For our example, we'll go ahead and create a server listener. Since the service needs to be bound to an available port, for our example we choose 8080, which is a port that we know to be unused on most computers. You may need to choose a different port depending upon what ports you have available. To see a list of the used ports on your computer open a command prompt and issue the command "netstat --a". It may produce a long listing so make sure the command prompt buffer sizes are set to allow scrolling. Compile the class to make sure you have everything correct.
Create a new C# console application project. Add a class called SampleServer
and paste in the following code. Add a reference to System.Runtime.Remoting
in the project. In addition, add a reference to the project containing the MyObject
.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace MyRemotingServer
{
public class SampleServer
{
public static int Main(string [] args)
{
TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(MyObject), "HelloWorld",
WellKnownObjectMode.SingleCall);
System.Console.WriteLine(
"Press the enter key to exit...");
System.Console.ReadLine();
return 0;
}
}
}
Create a Client To Use the Remotable Object
Now that we have our remotable object and a server object to listen for requests, let's create a client to use it. Our client will be very simple. It will connect to the server, create an instance of the object using the server, and then execute the HelloWorld method.
Create a new C# console application project. Add a class called SampleClient
and paste in the following code. Add a reference to System.Runtime.Remoting
in the project as well as a reference to the project containing the MyObject
.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using MyRemoting
namespace MyRemotingClient
{
public class SampleClient
{
public static int Main(string [] args)
{
TcpChannel chan = new TcpChannel();
ChannelServices.RegisterChannel(chan);
MyObject obj = (MyObject) Activator.GetObject(
typeof(MyRemoting.MyObject),
"tcp://localhost:8080/HelloWorld" );
if( obj.Equals(null) )
{
System.Console.WriteLine(
"Error: unable to locate server");
}
Else { Console.WriteLine(obj.HelloWorld());
}
return 0;
}
}
}
After you make all the applications ready, first run the server application and then run the client application to see that the client successfully invokes the methods on the remote object exposed by the server.
Test the Remoting Sample
Once you have created the projects and successfully compiled each of them you are ready to try it out. Assuming you chose a free TCP/IP port for the service, start the server executable. After the server successfully starts it will result in a console window being displayed with the message "Press the enter key to exit." The server is listening so you are now ready to run the client. Executing the client should result in "Hello World!" being displayed in a separate console window. The client window will then close while the server remains open and available.
If you have multiple computers available to you on a network you could execute the server on one machine and the client on another just to prove to yourself that it really is remoting. In order to run on separate machines you would need to change the reference to localhost in the sample client to point to the appropriate location.
.NET Remoting versus Distributed COM
In the past interprocess communication between applications was handled through Distributed COM, or DCOM. DCOM works well and the performance is adequate when applications exist on computers of similar type on the same network. However, DCOM has its drawbacks in the Internet connected world. DCOM relies on a proprietary binary protocol that not all object models support, which hinders interoperability across platforms. In addition, have you tried to get DCOM to work through a firewall? DCOM wants to communicate over a range of ports that are typically blocked by firewalls. There are a ways to get it to work, but they either decrease the effectiveness of the firewall (why bother to even have the firewall if you open up a ton of ports on it), or require you to get a firewall that allows support for binary traffic over port 80.
.NET Remoting eliminates the difficulties of DCOM by supporting different transport protocol formats and communication protocols. This allows .NET Remoting to be adaptable to the network environment in which it is being used.
.NET Remoting versus Web Services
Unless you have been living in a cave, or are way behind in your reading, you have probably read something about Web services. When you read the description of .NET Remoting it may remind you a lot of what you're read about Web services. That is because Web services fall under the umbrella of .NET Remoting, but have a simplified programming model and are intended for a wide target audience.
Web services involve allowing applications to exchange messages in a way that is platform, object model, and programming language independent. Web services are stateless and know nothing about the client that is making the request. The clients communicate by transferring messages back and forth in a specific format known as the Simple Object Access Protocol, or SOAP. (Want to get some funny looks in the hallway? Stand around in the hallway near the marketing department with your colleagues and discuss the benefits of using SOAP).
The following list outlines some of the major differences between .NET Remoting and Web services that will help you to decide when to use one or the other:
- ASP.NET based Web services can only be accessed over HTTP. .NET Remoting can be used across any protocol.
- Web services work in a stateless environment where each request results in a new object created to service the request. .NET Remoting supports state management options and can correlate multiple calls from the same client and support callbacks.
- Web services serialize objects through XML contained in the SOAP messages and can thus only handle items that can be fully expressed in XML. .NET Remoting relies on the existence of the common language runtime assemblies that contain information about data types. This limits the information that must be passed about an object and allows objects to be passed by value or by reference.
- Web services support interoperability across platforms and are good for heterogeneous environments. .NET Remoting requires the clients be built using .NET, or another framework that supports .NET Remoting, which means a homogeneous environment.
Summary
.NET Remoting is a powerful way to enable interprocess communication. It is more complicated to program against than Web services. You need to decide for yourself whether your standard architecture is to use .NET Remoting or Web services.
A given AppDomain may be further subdivided into numerous Context Boundaries. In a nutshell, a .NET context provides a way for a single AppDomain to partition .NET objects that have special similar execution requirements.