Remoting

Remoting

As we mentioned earlier, remoting is the process of communication between different operating system processes, regardless of whether they are on the same computer. It simplifies communication between objects living in different application domains, possibly on different computers, and between different contexts, possibly in different application domains. The remoting framework is built into the common language runtime and can be used to build sophisticated distributed applications. Some of the features provided by .NET remoting are as follows:

  • Proxy objects

  • Object passing

  • Activation models

  • Stateless and stateful objects

  • Channels and serialization

  • Lease-based lifetime

  • Hosting objects in IIS

The most basic remoting scenario requires a client application and a minimal host process. The host process must register specific object types with the runtime and specify the desired configuration details. Remoting itself can be thought of as an abstraction layer over a transport protocol that enables applications to instantiate objects that may reside on remote machines and work with them as if they were local. It is an interesting technology because it is removed from the underlying transport protocol. What this means is that, unlike DCOM, you have choices as to how your client and server processes talk to each other.

Currently, remoting supports two transport protocols: TCP/IP and HTTP. Each has its advantages, depending on your requirements. TCP/IP offers the better performance by far. It is basically a low-level binary protocol that enables virtually direct communication with the remote objects. This protocol tends to work well in an intranet environment in which you have unrestricted TCP port usage. Using TCP/IP becomes problematic when you need to support clients across multiple sites or over the Internet. Most corporations have firewalls that block anything but the standard TCP/IP ports, which would render a remoting application using a custom TCP/IP port unusable.

The solution is the HTTP protocol. Firewalls are almost always configured to allow traffic over TCP/IP port 80 (the port used by the World Wide Web). Using HTTP, your remoting applications can communicate freely over the span of the Internet. The downside is that HTTP is nowhere near as efficient as TCP/IP. When you specify HTTP as your remoting transport protocol, you basically end up with XML over HTTP. Serializing your objects into XML is not as compact as using a binary format. It increases the size of the payload, increases processing resources on both the client and server, and takes longer to transmit. This extra overhead means that a method call over HTTP costs more than one over TCP/IP. Will you notice the difference in casual use? Not really. But it does have implications for larger-scale applications. It s nothing to worry about, just something to keep in mind.

As far as requirements for objects capable of remoting go, there is only one that is significant: they must derive the MarshalByRefObject class. Notice that this is a built-in feature of COM+ classes because the ServicedComponent class has MarshalByRefObject as a base class. Now is a good time to look at an example.

A Simple Remoting Example

The simple example in this section helps demonstrate the lifetime of remoting within your applications and illustrates some of the architectural considerations. Called Simple Remoting and included on the companion CD, it consists of a host process and a client process. The host process is a lightweight application that opens a TCP channel for listening to remoting requests and registers a type with the common language runtime. Once it is registered, the type is available for remote instantiation through the specified channel. The example uses the type SimpleClass (derived from MarshalByRefObject) as the remoting object and contains two separate projects (a server project and a client project). Before we go any further, let s take a look at SimpleClass:

Public Class SimpleClass    Inherits MarshalByRefObject    Public Function GetDateTime() As Date       Return Now()    End Function    Public Function Hello() As String       Return "Hello World!"    End Function End Class

From the application s perspective, the critical part is the server project, which is responsible for registering the remoting object with the host runtime. The code for doing this is fairly simple and looks like the following:

Dim channel As New TcpChannel(9999) ChannelServices.RegisterChannel(channel) RemotingConfiguration.ApplicationName = "SimpleRemotingServer" Dim t As Type = Type.GetType("Server.SimpleClass") RemotingConfiguration.RegisterWellKnownServiceType(t, "SimpleClass", _    WellKnownObjectMode.SingleCall)

It is important to note that the type is available through remoting only when the host process is active. If the host process terminates at any time, all types registered by that process are immediately unregistered and cease to respond to any incoming requests. This includes objects that have already been instantiated. Thus, if the process terminates while a client is still working with the proxy, the client will experience a network failure on the next call through the proxy object. Figure 21-9 illustrates the lifetime of the Simple Remoting example. It emphasizes that once the SimpleClass type has been registered, it is available only during the lifetime of the server process.

Figure 21-9

Life cycle of the Simple Remoting example.

As you can see, we need to keep this process running in some form or another; otherwise, our client is out of luck. Speaking of the client, here is what it looks like.

Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Tcp Public Class Form1    Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code "    Dim sc As SimpleClass    Private Sub DateTimeButton_Click(ByVal sender As System.Object, _    ByVal e As System.EventArgs) Handles DateTimeButton.Click       If Not Initialize() Then Return       MsgBox(sc.GetDateTime(), MsgBoxStyle.DefaultButton1, _ "GetDateTime()")    End Sub    Private Sub HelloButton_Click(ByVal sender As System.Object, _    ByVal e As System.EventArgs) Handles HelloButton.Click       If Not Initialize() Then Return       MsgBox(sc.Hello(), MsgBoxStyle.DefaultButton1, "Hello()")    End Sub    Public Function Initialize() As Boolean       If sc Is Nothing Then          Dim chan As New TcpChannel()          ChannelServices.RegisterChannel(chan)          Dim t As Type = Type.GetType("Server.SimpleClass")          sc = Activator.GetObject(t, _ "tcp://localhost:9999/SimpleClass")          If sc Is Nothing Then             MsgBox("Could not initialize the remoting client. " & _                "Check your configuration.")             Return False          End If       End If       Return True    End Function End Class

From this example, you can see how the client initializes the SimpleClass proxy by making the request of the Activator class. An important configuration requirement that is not obvious here is that both the client class and the server class must reside in the same namespace. That is why both the server code and the client code refer to Server.SimpleClass. Both projects have a copy of the class, and their namespaces match. This allows the client to know the fully qualified type of the SimpleClass that is also known to the server process. The application itself should look like Figure 21-10.

Figure 21-10

Simple Remoting sample in action.

While this example will work, it is not the most desirable way to go about implementing remoting in an application especially in a larger-scale application. This observation leads us to a discussion of the best architecture for an application that uses remoting.

Architecture for Remoting

The .NET Framework SDK has many decent remoting examples, but they are not in-depth enough to help you decide on an implementation strategy. Calling remote objects is by definition an expensive process, requiring you to think very carefully about how a remote object is used. Often when we use objects in our applications, we don t worry about whether we are using properties or methods, and we are not usually concerned with when and how often we manipulate those objects. In a distributed application, however, these are extremely important considerations. With XML Web services, it is possible to make methods available selectively. With remoting, it is not quite so simple. You are working with a proxy for the original class, and by definition all public methods are available to the client process. However, there is a way around this issue: interfaces.

Interfaces are an important way to implement a class for remoting. Programming against a limited interface prevents unintentional use of an object. You can do this by creating a separate assembly that contains the public interfaces intended only for use by remoting clients. Figure 21-11 illustrates this concept.

Figure 21-11.

Suggested remoting architecture.

Programming against interfaces is important for larger-scale applications because it allows you to further control which methods are exposed to down-level clients. This technique gives you a greater level of control than just access protection for methods on any given class. We ve provided another sample program on the companion CD, called Architecting for Remoting, that demonstrates how to use this technique. There are three main components to the application, as outlined in Figure 21-11: the INorthwindDatabase interface, the Database class (which implements the INorthwindDatabase interface), and the MyClient project. The critical difference between this example and the previous one is that the client application has awareness only of the INorthwindDatabase interface. It does not have a copy of the target class and does not know how the class is implemented. Here is the interface we are talking about:

Public Interface INorthwindDatabase    ReadOnly Property Categories() As DataTable    ReadOnly Property Customers() As DataTable    ReadOnly Property Employees() As DataTable    ReadOnly Property OrderDetails() As DataTable    ReadOnly Property Orders() As DataTable    ReadOnly Property Products() As DataTable    ReadOnly Property Shippers() As DataTable    ReadOnly Property Suppliers() As DataTable End Interface

The next code example is the actual database class that was created to implement the INorthwindDatabase interface. Notice that the class contains other public methods that do not exist in the interface. As far as the class is concerned, these are utility methods that the client should not be able to call (the ExecuteQuery method, for example).

Requiring the client to use the interface, instead of the actual class definition, has two effects. First, it prevents the client from using methods it should not have access to. Second, it allows you to create other database classes based on the same interface and use them all interchangeably without having to make any modifications to the client application. The implementation class, in this example database, is derived from ServicedComponent instead of directly from MarshalByRefObject, for the sake of demonstrating how easy it is to support COM+ and remoting simultaneously.

Imports MyInterfaces Imports System.Data Imports System.Data.OleDb Imports System.EnterpriseServices ' The database class containing the implementation for the ' INorthwindDatabase interface Public Class Database    Inherits ServicedComponent    Implements MyInterfaces.INorthwindDatabase    Dim conn As OleDbConnection    Dim cmd As OleDbCommand    Dim da As OleDbDataAdapter    Public Sub New()       conn = New OleDbConnection( _        "Provider=Microsoft.Jet.OLEDB.4.0;" &          "Data Source=C:\Northwind.mdb")       cmd = New OleDbCommand("", conn)       da = New OleDbDataAdapter(cmd)    End Sub    Private Function ExecuteQuery(ByVal query As String) As DataTable       Dim t As New DataTable()       conn.Open()       cmd.CommandText = query       da.Fill(t)       conn.Close()       Return t    End Function    Public ReadOnly Property Categories() As DataTable _          Implements INorthwindDatabase.Categories       Get          Return ExecuteQuery("Select * From Categories")       End Get    End Property    Public ReadOnly Property Customers() As DataTable _          Implements INorthwindDatabase.Customers       Get          Return ExecuteQuery("Select * From Customers")       End Get    End Property    Public ReadOnly Property Employees() As DataTable _          Implements INorthwindDatabase.Employees       Get          Return ExecuteQuery("Select * From Employees")       End Get    End Property    Public ReadOnly Property OrderDetails() As DataTable _          Implements INorthwindDatabase.OrderDetails       Get          Return ExecuteQuery("Select * From [Order Details]")       End Get    End Property    Public ReadOnly Property Orders() As DataTable _          Implements INorthwindDatabase.Orders       Get          Return ExecuteQuery("Select * From Orders")       End Get    End Property    Public ReadOnly Property Products() As DataTable _          Implements INorthwindDatabase.Products       Get          Return ExecuteQuery("Select * From Products")       End Get    End Property    Public ReadOnly Property Shippers() As DataTable _          Implements INorthwindDatabase.Shippers       Get          Return ExecuteQuery("Select * From Shippers")       End Get    End Property    Public ReadOnly Property Suppliers() As DataTable _          Implements INorthwindDatabase.Suppliers       Get          Return ExecuteQuery("Select * From Suppliers")       End Get    End Property End Class

The server process is not very interesting. It registers the ServerProcess.Database class with the runtime and then sits there. The code is really no different from the server project in the Simple Remoting example. The client, on the other hand, is quite different. The client requests an object from the remoting channel that is based solely on the INorthwindDatabase interface. It has no reference to or knowledge of the underlying Database class and thus cannot call any methods that are not exposed by the INorthwindDatabase interface. Here is what the code looks like:

Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.Tcp Public Class Form1    Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code "    Dim northwindDB As MyInterfaces.INorthwindDatabase    Public Function Initialize() As Boolean       If northwindDB Is Nothing Then          Dim chan As New TcpChannel()          ChannelServices.RegisterChannel(chan)          Dim t As Type = Type.GetType( _             "MyInterfaces.INorthwindDatabase,MyInterfaces")          northwindDB = Activator.GetObject(t, _             "tcp://localhost:8086/NorthwindDB")          If northwindDB Is Nothing Then             MsgBox("Could not initialize the remoting client." & _                "Check your configuration.")             Return False          End If       End If       Return True    End Function    Private Sub CustomersButton_Click(ByVal sender As System.Object, _          ByVal e As System.EventArgs) Handles CustomersButton.Click       If Not Initialize() Then Return       QueryDataGrid.DataSource = northwindDB.Customers    End Sub    Private Sub EmployeesButton_Click(ByVal sender As System.Object, _          ByVal e As System.EventArgs) Handles EmployeesButton.Click       If Not Initialize() Then Return       QueryDataGrid.DataSource = northwindDB.Employees    End Sub    Private Sub CategoriesButton_Click(ByVal sender As System.Object, _          ByVal e As System.EventArgs) Handles CategoriesButton.Click       If Not Initialize() Then Return       QueryDataGrid.DataSource = northwindDB.Categories    End Sub    Private Sub OrderDetailsButton_Click _ (ByVal sender As System.Object, _          ByVal e As System.EventArgs) Handles OrderDetailsButton.Click       If Not Initialize() Then Return       QueryDataGrid.DataSource = northwindDB.OrderDetails    End Sub End Class



Upgrading Microsoft Visual Basic 6.0to Microsoft Visual Basic  .NET
Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET w/accompanying CD-ROM
ISBN: 073561587X
EAN: 2147483647
Year: 2001
Pages: 179

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net