Unless you have spent the last two years in hibernation, you must already be aware of XML Web Services and its powers. Despite all the attention Web Services have received as an ultimate solution to distributed computing, let us face the ground reality. There are still thousands of applications running on intranets and there would be thousands more that would be developed in future.
The goal of these applications is not to carry out cross–platform communication across heterogeneous systems (which is the strength of Web Services). In such cases there is no point in building these applications as Web Services as they may not be able to provide the desired performance and capabilities. Instead using .NET Remoting to carry out client–server communication would be an excellent solution.
An application boundary defines the scope of an application. It encompasses various resources critical to an application's execution, such as address space, executable code and the data used by the application. A typical multiprogramming execution environment, such as Windows, uses application boundaries to protect one application from affecting the execution of another application.
In this section, you'll learn about the application boundaries supplied by Windows and the .NET Framework. You'll understand how application boundaries protect applications from poorly designed or faulty code. You'll also learn how application boundaries make it difficult to design applications that want to communicate beyond application boundaries.
A process is an application under execution. Windows isolates processes from each other to ensure that code running in one process cannot adversely affect other processes. Windows achieves this isolation by creating a process boundary. A process boundary ensures that
Each process has its own virtual address space, executable code, and data.
A Windows process cannot directly access the code or data of another Windows process.
A Windows process runs only one application, so if an application crashes, it does not affect other applications.
Process boundaries are a good thing because they allow processes to coexist. However, it takes lot of system resources to create, monitor, and terminate a process. In addition, when the processor switches between the processes, the processor must save and reset the execution context of the processes. Often an application would involve several short-lived processes, which require the system to spend a lot of resources just for process management.
Application Domain Boundary
The Common Language Runtime (CLR) provides a managed execution environment for the .NET applications. The managed execution environment provides various services to the executing code; including cross-language integration, code access security, object lifetime management, and debugging and profiling support. This is why code executed by the CLR is also known as managed code.
Unlike Windows, the CLR can verify the type-safety of programs to guarantee that a program does not request resources outside of its own boundary. The characteristics of the CLR help provide isolation between running programs at a lower cost than the process boundary.
Instead of a process, the basic unit of isolation for running applications in the CLR is an application domain. An application domain (also known as an AppDomain) is the smallest execution unit for a .NET application. The CLR allows several application domains to run within a single Windows process and still provides the same level of isolation between applications as provided by a Windows process.
The application domains achieve isolation through application domain boundaries, which ensure that
Each application domain contains its own set of code, data, and configuration settings.
An application domain cannot directly access the code or data structures of another application domain.
Code running in one application domain cannot affect other application domains. The CLR can terminate an application domain without stopping the entire process.
Creating, monitoring, and maintaining an application domain uses fewer resources than performing the same operations with a process. In addition, the capability of an application domain to run multiple applications within the same process reduces the overhead of process switching. Thus, application domains increase the performance of the applications.
You can create an application domain in a program using the AppDomain class of System namespace. However, in most cases the application domains are created and managed by the runtime hosts that execute your code. Runtime hosts provide the environment to run managed code on behalf of the user. When you install the .NET Framework, you get three runtime hosts already configured—the Windows shell, ASP.NET, and Internet Explorer.
From the previous sections, you can see that both process and application domains provide a closely protected environment. As a result, objects in a process or an application domain cannot directly talk to objects in another process or application domain.
However, in the increasingly connected world, enterprises and users demand distributed applications. Distributed applications allow objects to talk across process boundaries. Often, distributed applications also meet the following objectives:
Establishes communication between objects that run in different application domains and processes whether on the same computer or across the Internet.
Enables enterprise application integration by establishing communication between objects that run on heterogeneous architectures.
Enables application availability by making sure that portions of an application continue to run even if some components are busy or have failed.
Provides increased security and scalability by dividing the application into several layers (or tiers).
Evolution of Distributed Applications
A well-designed distributed application has the potential to be more connected, more available, more scalable, and more robust than an application in which all components run on a single computer. This is a desirable model for an enterprise application.
Several efforts have been made to design frameworks for developing distributed applications. A few well-known frameworks are Distributed Computing Environment/Remote Procedure Calls (DEC/RPC), Microsoft Distributed Component Object Model (DCOM), Common Object Request Broker Architecture (CORBA), and Java Remote Method Invocation (RMI). Some of these implementations are widely deployed in enterprises.
However, modern business requirements are different from earlier days. Today, businesses seek solutions that can be developed rapidly, that integrate well with their legacy applications, and that interoperate well with their business partners. Each of the previously mentioned technologies failed to satisfy one or more of these requirements.
In 2000, Microsoft introduced the .NET Framework for designing next-generation, distributed applications. As you'll explore more in this book, the .NET Framework is specifically targeted to meet the needs of modern business whether the need is rapid development, integration, or interoperability.
Developing Distributed Applications Using the .NET Framework
The .NET Framework provides various mechanisms to support distributed application development. Most of this functionality is present in the following three namespaces of the Framework Class Library (FCL):
The System.Net Namespace—This namespace includes classes to create standalone listeners and custom protocol handlers to start from scratch, as well as to create your own framework for developing a distributed application. Working with the System.Net namespace directly requires a good understanding of network programming.
The System.Runtime.Remoting Namespace—This namespace includes the classes that constitutes the .NET remoting framework. The .NET remoting framework enables communication between objects living in different application domains whether or not they are on the same computer. Remoting provides an abstraction over the complexities of network programming and exposes a simple mechanism for interapplication domain communication. The key objectives of .NET remoting are flexibility and extensibility.
The System.Web.Services Namespace—This namespace includes the classes that constitute the ASP.NET Web services framework. ASP.NET Web services enable objects living in different application domains to exchange messages using standard protocols such as HTTP and SOAP. ASP.NET Web services, when compared to remoting, provide a much higher level of abstraction and simplicity. The key objectives of ASP.NET Web services are ease of use and interoperability with other systems.
Both .NET remoting and ASP.NET Web services provide a complete framework for designing distributed applications. Most programmers will use either .NET remoting or ASP.NET Web services instead of building a distributed programming framework from scratch using the System.Net namespace classes.
The functionality offered by .NET Remoting and ASP.NET Web services appears very similar to each other. In fact, ASP.NET Web services are actually built on the .NET Remoting infrastructure. It is also possible to design Web services using .NET remoting. Given the amount of similarity, how do you choose one over another in your project? Simply put, the decision depends on the type of application you want to create. You'll use
.NET Remoting when both of the endpoints (client and server) of a distributed application are in your control. This might be a case when an application has been designed for use within a corporate network.
ASP.NET Web services when one of the endpoints of a distributed application is not in your control. This might be a case when your application is interoperating with your business partner's application.
.NET Remoting Architecture
.NET remoting enables objects in different application domains to talk to each other. The real strength of remoting is in enabling communication between objects when their application domains are separated across the network. In this case, remoting transparently handles details related to network communication.
Before getting into details, let's first answer a basic question—How can remoting establish cross-application domain communication when an application domain does not allow direct calls across its boundary?
Remoting takes an indirect approach to application domain communication by creating proxy objects . Both application domains communicate with each other using the following steps:
When a client object wants to create an instance of the server object, the remoting system at the client side instead creates a proxy of the server object. The proxy object lives at the client but behaves just like the remote object; this leaves the client with the impression that the server object is in the client's process.
In a simplified view of .NET remoting, note that the client and server communicate indirectly through a proxy object.
When the client object calls a method on the server object, the proxy passes the call information to the remoting system on the client. This remoting system in turn sends the call over the channel to the remoting system on the server.
The remoting system on the server receives the call information and, on the basis of it, invokes the method on the actual object on the server (creating the object if necessary).
The remoting system on the server collects all the results of the method invocation and passes them through the channel to the remoting system on the client.
The remoting system at the client receives the response of the server and returns the results to the client object through the proxy.
The process of packaging and sending method calls among the objects across the application boundaries via serialization and deserialization, as shown in the preceding steps, is also known as marshalling.
Now that you have a basic idea of how .NET remoting works, its time to get into details. In the next few sections, I'll explain the various key components and terminology of .NET remoting.
Remotable objects are objects that can be marshalled across the application domains. In contrast, all other objects are known as non-remotable objects. There are two types of remotable objects:
Marshal-by-value (MBV) Objects—These objects are copied and passed out of the server application domain to the client application domain.
Marshal-by-reference (MBR) Objects—These objects are accessed on the client side using a proxy. The client just holds a reference to these objects.
MBV objects reside on the server. However, when the client invokes a method on the MBV object, the MBV object is serialized, transferred over the network, and restored on the client as an exact copy of the server-side object. The method is then invoked directly on the client. When this happens, the MBV object is no longer a remote object. Any method calls to the object do not require any proxy object or marshalling because the object is locally available.
The MBV objects can provide faster performance by reducing the number of network roundtrips, but in the case of large objects, the time taken to transfer the serialized object from the server to the client can be very significant. Further, MBV objects do not allow you the flexibility to run the remote object in the server environment.
A MBV object can be created by declaring a class with the Serializable attribute; for example
' Define a MBV remoting object
Public Class MyMBVObject
' Implementation details
End ClassIf a class needs to control its own serialization, it can do so by implementing the ISerializable interface as shown here:
' Define a MBV remoting object
Public Class MyMBVObject
' Class details ...
'Implement custom serialization here
Public Sub GetObjectData( _
ByVal info As SerializationInfo, _
ByVal context As StreamingContext)
' Serialization details ...
End ClassMarshal-by-Reference Objects
MBR objects are remote objects. They always reside on the server, and all methods invoked on these objects are executed at the server side. The client communicates with the MBR object on the server using a local proxy object that holds the reference to the MBR object.
Although the use of MBR objects increases the number of network roundtrips, they are a good choice when the objects are prohibitively large or when the functionality of the object is only available in the server environment on which it is created.
An MBR object can be created by deriving from the System.MarshalByRefObject class; for example,
' Define a MBR remoting object
Public Class MyMBRObject
' Class details ...
Create and consume a .NET Remoting object: Select a channel protocol and a formatter. Channel protocols include TCP and HTTP. Formatters include SOAP and binary.
Channels are the objects that transport messages across remoting boundaries such as application domains, processes, and computers. When a client calls a method on a remote object, the details of the method call are transported to the remote object through a channel. Any results returned from the remote object are communicated back to the client again through the same channel.
The .NET remoting framework ensures that before a remote object can be called, it has registered at least one channel with the remoting system on the server. Similarly, the client object should specify a channel before it can communicate with a remote object. If the remote object offers more than one channel, the client can connect using the channel that best suits its requirements.
A channel has two endpoints. The channel object at the receiving end of a channel (the server) listens to a particular protocol using the specified port number, whereas the channel object at the sending end of the channel (the client) sends information to the receiving end using the protocol and port number specified by the channel object on the receiving end.
Formatters are the objects used to encode and serialize data into messages before they are transmitted over a channel.
To participate in the .NET remoting framework, a formatter class must implement the IFormatter interface. The .NET Framework packages two formatter classes for common scenarios—the BinaryFormatter class and the SoapFormatter class. If you want to use a different formatter, you can define your own formatter class by implementing the IFormatter interface.
The SOAP Formatter
SOAP (Simple Object Access Protocol) is a relatively straightforward, XML-based protocol for exchanging types and messages between applications. SOAP is an extensible and modular protocol; it is not bound to a particular transport mechanism such as HTTP or TCP.
The SOAP formatter is implemented in the SoapFormatter class of the System.Runtime.Serialization.Formatters.Soap namespace.
SOAP formatting is an ideal way of communicating between applications that use incompatible architectures. However, SOAP is very verbose. SOAP messages require more bytes to represent data than the equivalent binary messages.
The Binary Formatter
Unlike SOAP, the binary format used by the .NET Framework is proprietary and can be understood only within .NET applications. However, as compared to SOAP, the binary format of representing messages is very compact and efficient.
The binary formatter is implemented in the BinaryFormatter class of the System.Runtime.Serialization.Formatters.Binary namespace.
Channels and Formatters
The HTTP channel uses the SOAP formatter as its default formatter to transport messages to and from the remote objects. The HTTP channel uses SoapClientFormatterSinkProvider and SoapServerFormatterSinkProvider classes to serialize and deserialize messages using SoapFormatter. You can create industry-standard XML Web services by using the SOAP formatter with the HTTP channel.
The TCP channel uses the binary format by default to transport messages to and from the remote object. The TCP channel uses BinaryClientFormatterSinkProvider and BinaryServerFormatterSinkProvider classes to serialize and deserialize messages using BinaryFormatter.
However, channels are configurable. You can configure the HTTP channel to use the binary formatter or a custom formatter instead of the SOAP formatter. Similarly, the TCP channel can be configured to use the SOAP formatter or a custom formatter instead of the binary formatter.
Figure 3.2 compares the various combinations of channels and formatters on the scale of efficiency and compatibility. The protocols at the top of the list are the most efficient, while those at the bottom of the list are most interoperable. You can use this information to decide which combination of channel and formatter you would choose in a given scenario.
Remote Object Activation
Between the two types of objects that you have seen (MBV objects and MBR objects), only MBR objects can be activated remotely. No remote activation is needed in the case of MBV objects because the MBV object itself is transferred to the client side.
Remotable Members An MBR object can remote the following types of members:
Non-static public methods
Non-static public properties
Non-static public fields
Based on the activation mode, an MBR object is classified into one of the following two categories:
Server-activated objects (SAO) are those remote objects whose lifetime is directly controlled by the server.
When a client requests an instance of a server-activated object, a proxy to the remote object is created in the client's application domain. The remote object is only instantiated (or activated) on the server when the client calls a method on the proxy object.
Server-activated objects provide limited flexibility because they can only be instantiated using their default (parameter-less) constructors.
Well-Known Objects Remote objects activated in SingleCall or Singleton activation mode are also known as well-known objects.
There are two possible activation modes for a server-activated object:
SingleCall activation mode
Singleton activation mode
SingleCall Activation Mode
In the SingleCall activation mode, an object is instantiated for the sole purpose of responding to just one client request. After the request is fulfilled, the .NET remoting framework deletes the object and reclaims its memory.
Objects activated in the SingleCall mode are also known as stateless because the objects are created and destroyed with each client request; therefore, they do not maintain state across requests. This behavior of SingleCall mode allows for greater server scalability as an object consumes server resources only for a small period, therefore allowing the server to allocate resources to other objects.
The SingleCall activation mode is a desired solution when
The overhead of creating an object is not significant.
The object is not required to maintain its state.
The server needs to support a large number of requests for the object.
The object needs to be supported in a load-balanced environment.
Load-Balancing and SingleCall Activation Sometimes to improve the overall efficiency of an application, it might be hosted on multiple servers that share the incoming requests to the application. In this case, a request can go to any of the available servers for processing. This scenario is called a load-balancing environment.
Because the SingleCall objects are stateless, it does not matter which server processes requests for such objects. For this reason, SingleCall activation is ideally suited for load-balanced environments.
Common scenarios of the SingleCall activation mode are those applications in which the object is required by the client to do a small amount of work and then the object is no longer required. Some common examples are retrieving the inventory level for an item, displaying tracking information for a shipment, and so on.
Singleton Activation Mode
In the Singleton activation mode, at most there will be one instance of the remote object regardless of the number of clients accessing it.
A Singleton-mode object can maintain state information across method calls. For this reason, such objects are also sometimes known as stateful objects. The state maintained by the Singleton-mode object is globally shared by all of its clients. This generally means that you should not store any state in Singleton-mode objects. But there are circumstances (such as keeping track of usage statistics) in which it can make sense to store shared state.
A Singleton object does not exist on the server forever. Its lifetime is determined by the lifetime lease of the object. I'll discuss lifetime leases later in the chapter.
A Singleton object is a desired solution when
The overhead of creating an object is substantial.
The object is required to maintain its state over a prolonged period.
Several clients need to work on the shared state.
Singleton activation mode is useful in scenarios such as in a chat server in which multiple clients talk to the same remote object and share data between one another through this object.
Client-activated objects (CAO) are those remote objects whose lifetime is directly controlled by the client. This is in direct contrast with SAOs, where the server, not the client, has the complete control over the lifetime of the objects.
Client-activated objects are instantiated on the server as soon as the client requests the object to be created. Unlike an SAO, a CAO does not delay the object creation until the first method is called on the object.
A CAO can be created using any of the available constructors for the class. A typical CAO activation involves the following steps:
When the client attempts to create an instance of the server object, an activation request message is sent to the remote server.
The server then creates an instance of the requested class using the specified constructor and returns an ObjRef object to the client application that invoked it. The ObjRef object contains all the required information to generate a proxy object that is capable of communicating with a remote object.
The client uses the ObjRef object to create a proxy for the server object on the client side.
An instance of a CAO serves only the client responsible for its creation, and the CAO doesn't get discarded with each request. For this reason, a CAO can maintain state with each client that it is serving, but unlike the Singleton SAO, different CAOs cannot share a common state.
The lifetime of a CAO is determined using lifetime leases. I'll talk more about this topic shortly in a section titled "Lifetime Leases."
A CAO is a desired solution when
The clients want to maintain a private session with the remote object.
The clients want to have more control over how the objects are created and how long they will live.
A CAO is useful in scenarios such as entering a complex purchase order in which multiple roundtrips are involved and clients want to maintain their own private state with the remote object.
Comparing the Object Activation Techniques
Based on the discussions in the previous section, the various object activation techniques can be compared as shown in Figure 3.3.
The SingleCall server activation has maximum scalability because such objects occupy server resources for the minimum amount of the time. This enables the server to allocate its resources between a large numbers of clients.
On the other hand, the client activation of remote objects offers maximum flexibility because you have complete control over the construction and lifetime of the remote object.
Applying .NET Remoting
Applying .NET Remoting
So far, I have discussed the architecture and various concepts related to the .NET remoting. In this section, you will learn how to apply these concepts to see remoting in action. In particular, you will learn how to
Create a remotable class.
Create a Server-activated object.
Create a Client-activated object.
Use configuration files to configure the remoting framework.
Use interface assemblies to compile remoting clients.
Creating a Remotable Class
Creating a remotable class is simple. All you need to do is to inherit a class from the MarshalByRefObject class. Step By Step 3.1 creates a remotable class named DbConnect. This class connects to a specified SQL Server database and allows you to execute a SELECT SQL statement using its ExecuteQuery() method.
STEP BY STEP 3.1: Creating a Remotable Class
Launch Visual Studio .NET. Select File, New, Blank Solution, and name the new solution 310C03. Click OK.
Add a new Visual Basic .NET Class library named StepByStep3-1 to the solution.
In the Solution Explorer, rename the default Class1.vb to DbConnect.vb.
Open the DbConnect.vb class and replace the code with the following code:
' Marshal-by-Reference Remotable Object
Public Class DbConnect
Private sqlconn As SqlConnection
' Default constructor connects to the Northwind
Public Sub New()
sqlconn = New SqlConnection( _
"data source=(local);" & _
"initial catalog=Northwind;" & _
"Created a new connection " & _
"to the Northwind database")
' Parameterized constructor connects to the
' specified database
Public Sub New(ByVal DbName As String)
sqlconn = New SqlConnection( _
"data source=(local);" & _
"initial catalog=" & DbName & ";" & _
"Created a new connection " & _
"to the " & DbName & " database")
Public Function ExecuteQuery( _
ByVal strQuery As String) As DataSet
Console.Write("Starting to execute " & _
' Create a SqlCommand to represent the query
Dim sqlcmd As SqlCommand = _
sqlcmd.CommandType = CommandType.Text
sqlcmd.CommandText = strQuery
' Create a SqlDataAdapter object
' to talk to the database
Dim sqlda As SqlDataAdapter = _
sqlda.SelectCommand = sqlcmd
' Create a DataSet to hold the results
Dim ds As DataSet = New DataSet()
' Fill the DataSet
Catch ex As Exception
"Error executing query")
ExecuteQuery = ds
End ClassSelect Build, Build StepByStep3-1. This step packages the remotable class into the file StepByStep3-1.dll, which is located in the bin or directory of your project. You can navigate to it through the Solution Explorer: Just select the project and click the Show All Files button in the Solution Explorer toolbar.
You've now created a remotable class, but it cannot yet be directly called from client application domains. For a remotable class to be activated, you need to connect the class to the remoting framework. You'll learn how to do that in the next section.
Creating a Server-Activated Object
A remotable class is usually connected with the remoting framework through a separate server program. The server program listens to the client request on a specified channel and instantiates the remote object or invokes calls on it as required.
It is a good idea to keep the remotable class and server program separate; this enables the design to be modular and the code to be reusable.
In this section, I'll show you how to create a remoting server. Here's an overview of the steps that the remoting server must take.
Create a server channel that listens on a particular port to the incoming object activation requests from other application domains. The following code segment shows how to create a TCP server channel and an HTTP server channel:
' Register a TCP server channel on port
Dim channel As TcpServerChannel = _
' Register a HTTP server channel on port
Dim channel As HttpServerChannel = _
New HttpServerChannel(1234)Register the channel with the remoting framework. This tells the framework which requests should be directed to this particular server. This registration is performed through the RegisterChannel() method of the ChannelServices class:
' Register the channel with remoting framework
ChannelServices.RegisterChannel(channel)Register the remotable class with the remoting framework. This tells the framework which classes this particular server can create for remote clients. For a server-activated object, this registration is performed using the RegisterWellKnownServiceType() method of the RemotingConfiguration class, as shown here:
' Register a remote object with the remoting framework
GetType(DbConnect), "DbConnect", _
WellKnownObjectMode.SingleCall)Here, the first parameter is the type of the remotable class. The second parameter specifies the uniform resource identifier (URI) through which the server publishes the location of the remote object. The last parameter specifies the activation mode. The activation mode can be one of the two possible values of the WellKnownObjectMode enumeration—SingleCall or Singleton.
Accessing an Object Through Multiple Channels From steps 2 and 3, you can note that the channel registration and the remote object registration are not related. In fact, a remote object can be accessed through all registered channels.
With the channel and class both registered, the remoting server is ready to go. The remoting framework will direct all requests for that class via that channel to the registered server.
As I discussed, earlier, an SAO can be activated in two different modes—SingleCall and Singleton. In the next few sections, I'll cover how to create a remoting server for activating objects in each of these modes. I'll also tell the story on the other side of the channel; that is, how to connect the client program to the remoting framework so that it can instantiate the SAO and call methods on it.
Registering a Remotable Class As a Server-Activated Object Using the SingleCall Activation Mode
In this section, I'll demonstrate how to create a server that exposes the remotable class through the remoting framework. The server process here will be a long running user interface-less process that will continue to listen for incoming client requests on a channel.
Ideally, you should write this type of server program as a Windows service or use an existing Windows service such as Internet Information Services (IIS) to work as a remoting server. But I have chosen to write the server program as a console application mainly because I'll use the console Window to display various messages that will help you understand the workings of the remoting server.
Later in this chapter, in the section "Using IIS As an Activation Agent," I'll cover how to use IIS as a remoting server. I'll talk about Windows services in Chapter 6, "Windows Services."
STEP BY STEP 3.2: Registering a Server-Activated Object Using the SingleCall Activation Mode
Add a new Visual Basic .NET Console application named StepByStep3-2 to the solution.
In the Solution Explorer, right-click the project StepByStep3-2 and select Add Reference from the context menu. In the Add Reference dialog box (see Figure 3.4), select the .NET tab, select the System.Runtime.Remoting component from the list view, and click the Select button. Now select the Projects tab, select the Project named StepByStep3-1 (which contains the remotable object) from the list view, and click the Select button. Both the selected projects then appear in the Selected Components list, as shown in Figure 3.4. Click OK.
In the Solution Explorer, rename the default Module1.vb module to DbConnectSingleCallServer.vb. Open the file and change the name of the module to DbConnectSingleCallServer in the module declaration.
Namespace Naming Note that although the project is named StepByStep3-1, the corresponding namespace is named StepByStep3_1. That's because the .NET Framework considers a dash to be an illegal character in a namespace name.
Add the following Imports directives above the module declaration:
Imports System.Runtime.Remoting.Channels.TcpAdd the following code in the Main() procedure:
Public Sub Main()
' Create and Register a TCP server channel
' that listens on port
Dim channel As TcpServerChannel = _
' Register the service that publishes
' DbConnect for remote access in SingleCall mode
GetType(StepByStep3_1.DbConnect), "DbConnect", _
Console.WriteLine("Started server in the " & _
Console.WriteLine("Press to terminate " & _
End SubRight-click on the StepByStep3-2 project in the Solution Explorer and select Properties. Change the Startup object to DbConnectSingleCallServer.
Build the project. This step creates a remoting server that is capable of registering the StepByStep3_1.DbConnect class for remote invocation using the SingleCall activation mode.
Step by Step 3.2 uses a receiver TCP channel (TcpServerChannel) to register a remotable class with the remoting framework. However, converting this program to use HTTP channel is not difficult—you just need to change all instances of Tcp to Http.
Step By Step 3.2 creates a remoting host that listens on port 1234. This is an arbitrary port number that might or might not work on your computer. A good idea is to check whether a port is already in use by some other application before running this program. You can do this from the command line on a particular computer by using the Windows netstat command.
This suggestion works only in a test scenario. It is not reasonable to instruct a customer to check whether the port is available before he starts the application. If the application will run entirely on your company's network, you can safely use a port in the private port range of 49152 through 65535—provided, of course, that the port number you choose is not used by any other internal application. In case you are distributing the application, you should get a port number registered with the IANA (Internet Assigned Numbers Authority). You can see a list of already assigned port numbers at http://www.iana.org/assignments/port-numbers.
Instantiating and Invoking a Server-Activated Object
At this stage, you have a remotable object as well as a remoting server ready. In this section, I'll show you how to create a remoting client and use it to send messages to the remoting server to activate the remote object. In order to achieve this, the remoting client needs to take the following steps:
Create and register a client channel that is used by the remoting framework to send messages to the remoting server. The type of the channel used by the client should be compatible with the channel used by server. The following examples show how to create a TCP client channel and an HTTP client channel:
' Create and register a TCP client channel
Dim channel As TcpClientChannel = _
' Create and register a HTTP client channel
Dim channel As HttpClientChannel = _
Client Channel Registration You do not specify a port number when you register the client channel. The port number is instead specified at the time you register the remote class in the client's domain.
Register the remotable class as a valid type in the client's application domain. This registration is performed using the RegisterWellKnownClientType() method of the RemotingConfiguration class as shown here:
' Register the remote class as a valid
' type in the client's application domain
GetType(DbConnect), "tcp://localhost:1234/DbConnect")Here, the first parameter is the type of the remotable class. The second parameter specifies the uniform resource identifier (URI) through which the server publishes the location of the remote object. Localhost maps to your local development machine. If the remote object is on some other computer, you'll replace localhost with the name of the computer.
Instantiating a Server-Activated Object You can only instantiate an SAO at client side using its default constructor.
Instantiate the SAO on the server. You can only use the default constructor.
' Instantiate the remote object
DbConnect dbc = new DbConnect()I'll demonstrate the preceding steps in Step by Step 3.3. In this example, I'll create the client program as a Windows application that accepts a SQL statement from the user and passes it to the remotable object. The rows returned by the remotable object are displayed in a DataGrid control.
STEP BY STEP 3.3: Instantiating and Invoking a Server-Activated Object
Add a new Visual Basic .NET Windows Application named StepByStep3-3 to the solution.
Add references to the .NET assembly System.Runtime.Remoting and the project StepByStep3-1 (the remotable class assembly).
In the Solution Explorer, delete the default Form1.vb. Add a new form named DbConnectClient.vb. Set the new form as the Startup object for the project.
Add the following directives to the form's module:
Imports StepByStep3_1Place two GroupBox controls, a TextBox control (txtQuery), a Button control (btnExecute) and a DataGrid control (dgResults) on the form. Set the Multiline property of txtQuery to True.
Add the following code to the form directly after the designer-generated code:
' Declare a Remote object
Dim dbc As DbConnectDouble-click the form and add the following code in the Load event handler:
Private Sub DbConnectClient_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
' Register a TCP client channel
Dim channel As TcpClientChannel = _
' Register the remote class as a valid
' type in the client's application domain
' Instantiate the remote class
dbc = New DbConnect()
End SubDouble-click the Button control and add the following code in the Click event handler:
Private Sub btnExecute_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnExecute.Click
' Invoke a method on the remote object
Me.dgResults.DataSource = _
dgResults.DataMember = "Results"
Catch ex As Exception
"Query Execution Error")
End SubRight-click on the name of the solution in the Solution Explorer window and select Properties. This opens the Solution Property Pages dialog box. In the dialog box, select the Multiple Startup Projects check box, select the action Start for StepByStep3-2 and StepByStep3-3, and set the action to None for other projects as shown in Figure 3.6. Make sure that StepByStep3-2 is placed above StepByStep3-3. If it isn't already there, click the Move Up and Move Down buttons to get the right order.
Build the project. Select Debug, Start to run the project. You should see a command window displaying a message that the server is started in the SingleCall mode.
Shortly afterward, you'll see a Windows form for the client program. Enter a query in the text box and click the Execute Query button. The client invokes a method on the remote object and binds the results from the remote method to the DataGrid control.