Remoting

Team-Fly    

 
Application Development Using Visual Basic and .NET
By Robert J. Oberg, Peter Thorsteinson, Dana L. Wyatt
Table of Contents
Chapter 10.  .NET Framework Classes


Remoting technology provides a summary of the key concepts in the .NET Application Model. While a complete discussion of remoting is beyond the scope of this book, a brief introduction provides a powerful example of how metadata and marshal by reference (MBR) work. Remoting also provides a mechanism to have executable servers.

Unlike remoting in Microsoft's COM technology, there is a minimal amount of infrastructure programming required. What infrastructure program is required allows the programmer either a degree of flexibility or the ability to customize remoting for their particular applications.

The .NET Framework provides two ways to provide connections between two applications on different computers. Web services, discussed in Chapter 15, enable computers that do not host the CLR to communicate with computers that do. The remoting technology discussed here builds distributed applications between computers that host the CLR.

Remoting Overview

The key parts of remoting are

  • Interception , which allows for message generation for communication over the channels.

  • Formatters to put the messages into a byte stream that is sent over the channel. These are the same formatters that were discussed in the section on serialization.

  • Communication channel for transport of messages.

Interception

Proxies and stubs (referred to in .NET as dispatchers) transform the function calls on the client or server side into messages that are sent over the network. This is called interception, because the proxies and dispatchers intercept a method call to send it to its remote destination. Unlike COM, metadata provides the information so the CLR can generate the proxies and stubs for you.

A proxy takes the function call off the stack frame of the caller and transforms it into a message. The message is then sent to its destination. A dispatcher takes the message and transforms it into a stack frame so that a call can be made to the object.

For example, assume the UnregisterCustomer method from the Customer assembly runs in one application domain and is called from another. It makes no difference if the application domains are in the same process or on the same machine.

The proxy would take the integer id argument on the stack frame of the client making the call and put it in a message that encoded the call and its argument. On the server side, the dispatcher would take that message and create a function call on the server's stack for the call UnregisterCustomer(int id) and make that call into the object. The client and server code do not know that they are being remoted .

Channels and Formatters

The formatter converts the message into a byte stream. The .NET Framework comes with two formatters, binary and SOAP (text-based XML, discussed in Chapter 15). The byte stream is then sent over a communication channel.

The .NET Framework comes with two channels, although you can write your own. The HTTP channel uses the HTTP protocol and is good for communicating over the Internet or through firewalls. The TCP channel uses the TCP (sockets) protocol and is designed for high-speed communication. You have four permutations of formatters and transport: binary over TCP, binary over HTTP, SOAP over HTTP, and SOAP over TCP.

Remote Objects

Clients obtain a proxy by activating a remote object. Remote objects must derive from MarshalByRefObject because you work with a proxy to the object reference, not with the object reference itself. This is the same concept discussed in the section on contexts, where marshal by reference is also used to access context bound objects.

Local objects passed as method parameters from one application domain to another can be passed by value ( copied ) or by reference.

To be passed by value, they must be serializable. The object is serialized, sent across the transport layer, and recreated on the other side. We have already seen an example of this in the application domain example.

To be passed by reference, the class must derive from MarshalByRef-Object . The Remoting example illustrates pass by reference.

Remote objects can either be server-activated or client-activated. Server-activated objects are not created until the first method call on the object. Server-activated objects come in two flavors. SingleCall objects are stateless. Each method causes a new object to be created. Singleton objects can be used by multiple client activation requests . Singleton objects can maintain state. SingleCall objects will scale better than Singleton objects because they do not retain state and can be load balanced.

Client-activated objects are activated when the client requests them. While they can last for multiple calls and hold state, they cannot store information from different client activations. This is similar to calling CoCreateInstanceEx in DCOM.

Activation

Objects are activated on the client side in one of three ways by using the Activator class.

  • Activator.GetObject is used to get a reference to a server-activated object.

  • Activator.CreateInstance is used to create a client-activated object. You can pass parameters to the object's constructor using one of the overloaded CreateInstance methods that takes an array of objects to be passed to the constructor.

  • The VB.NET New syntax can be used to create a server- or a client-activated object. A configuration file is used to describe how New should be used.

Sample Remotable Object

For our Remoting example, we remote our Customers object from the Customer assembly. In the Remoting example directory there are two solutions. One represents the client program, the other the server program. Each can be built independently of the other. Start the server program first. Notice that it waits for a client request. You can then run the client program, which will run against objects that live inside of the server. We will discuss the details of the client and server code and output in the next few sections.

Notice that we only had to make two simple changes to our object. The Customers class in the server project had to be made remotable by inheriting from MarshalByRefObject .

 Public Class  Customers  Inherits  MarshalByRefObject  Implements ICustomer ... End Class 

The CustomerListItem that will be to be transferred by value had to be made serializable.

 <  Serializable  ()> Public Structure  CustomerListItem  Public CustomerId As Integer    Public FirstName As String    Public LastName As String    Public EmailAddress As String End Structure 
Sample Remoting Program

In the Remoting example the client accesses a server-activated object. The server is the TcpServerChannel class that uses a binary format with the TCP protocol. The channel will use port 8085. The server registers the type being remoted, the endpoint name to refer to this object, and the type of activation. The server then waits for client requests.

 Dim chan As TcpServerChannel = _    New TcpServerChannel(8085) ChannelServices.RegisterChannel(chan) Dim assem As System.Reflection.Assembly = _    System.Reflection.Assembly.Load("Customer") Dim type As Type = assem.GetType("Customer.Customers") RemotingConfiguration.RegisterWellKnownServiceType(_    type, _    "AcmeCustomer", _    WellKnownObjectMode.Singleton) ... 

The server has to be started before the client program can access the object.

The client sets up a TcpClientChannel object and then connects to the object. It specifies the type of the object it wants and the endpoint where the server is listening for object requests. If you want to run the client and server on separate machines, substitute the server machine name for localhost in the endpoint. Unlike COM location transparency, the client has to specify a specific endpoint; there is no redirection through an opaque registry entry.

 Dim chan As TcpClientChannel = New TcpClientChannel() ChannelServices.RegisterChannel(chan) ... Dim assem As System.Reflection.Assembly = _    System.Reflection.Assembly.Load("Customer") Dim type As Type = assem.GetType("Customer.Customers") Dim obj As Customers = _    Activator.GetObject(_    type, _    "tcp://localhost:8085/AcmeCustomer") If obj Is Nothing Then    System.Console.WriteLine("Could not locate server") Else   ... 

The client then uses the proxy to make calls on the object as if it were a local instance.

 Dim bRet As Boolean = _    RemotingServices.IsTransparentProxy(obj) ... Dim ar As ArrayList ar = obj.GetCustomer(-1) ShowCustomerArray(ar) obj.RegisterCustomer(_    "Boris", "Badenough", "boris@no-goodnicks.com") Console.WriteLine() ar = obj.GetCustomer(-1) ShowCustomerArray(ar) 

To run the program, start the server program in one console window and then start the client program in another console window.

The output depends on what kind of server-activated object is being activated. If the server activation type is Singleton , which supports the maintenance of state, you get the behavior you would expect from the nonremoted case. A new customer is added, and you find that new customer in the list when you ask for all the existing customers. As you would expect, the initial activate call results in the Customers constructor being called once for each server invocation, no matter how many times the client program is run.

graphics/codeexample.gif
 Customers Constructor: AppDomain Client.exe Thread 111 Context 0 RegisterCustomer: AppDomain Client.exe Thread 111 Context 0 RegisterCustomer: AppDomain Client.exe Thread 111 Context 0 Object reference a proxy?: True Client: AppDomain Client.exe Thread 111 Context 0 1   Rocket         Squirrel       rocky@frosbitefalls.com 2   Bullwinkle     Moose          moose@wossamotta.edu 1   Rocket         Squirrel       rocky@frosbitefalls.com 2   Bullwinkle     Moose          moose@wossamotta.edu 3   Boris          Badenough      boris@no-goodnicks.com 

If the activation type is SingleCall , which creates a new object instance for every method call, the results are quite different. Four different objects are created. The first object is created by the initial activate request. The second is created by the initial call to GetCustomer . The third object is created by the RegisterCustomer call. The fourth object is created by the second call to GetCustomer . The last object created never sees the new customer because no state is saved. Note that the shared nextCustId member of the Customer class is treated as a shared member with respect to the new object instances of the Customer class, just as you would expect. Same client code, different results! Since the object is already activated, if you run the client program a second time for the same server invocation, the Customers constructor will be called only three times.

 Customers Constructor: AppDomain Client.exe Thread 111 Context 0 RegisterCustomer: AppDomain Client.exe Thread 111 Context 0 RegisterCustomer: AppDomain Client.exe Thread 111 Context 0 Object reference a proxy?: True Client: AppDomain Client.exe Thread 111 Context 0 3   Rocket         Squirrel       rocky@frosbitefalls.com 4   Bullwinkle     Moose          moose@wossamotta.edu 8   Rocket         Squirrel       rocky@frosbitefalls.com 9   Bullwinkle     Moose          moose@wossamotta.edu 

Since the client uses a proxy, the object executes inside the server's application domain, but on a different thread than the main server thread. The object's constructor is not called until the first method call on the object. Notice how in both cases we have remoted an ArrayList of types without any special work aside from making the type serializable. The presence of metadata makes the programmer's work much easier.

Metadata and Remoting

In order for the client to request an object of a specific type, metadata about the type has to be available to the client. For some applications, a reference can be made to the actual assembly where the object is stored.

For many applications, however, you do not want to give the client access to your source code. For the metadata that the client needs, a reference needs to be made only to an object that has none of the implementation details.

One way to do this is to build a version of the object that has methods with no implementation. This interface class can then be built into an assembly that can be given to the client. You can throw the System.NotSupported-Exception in the methods if you wish to make sure it is never used by mistake for the real object.

 <Serializable()> Public Structure CustomerListItem    Public CustomerId As Integer    Public FirstName As String    Public LastName As String    Public EmailAddress As String End Structure ... Public Class Customers    Inherits MarshalByRefObject    Implements Icustomer    Public Function  RegisterCustomer  (_     ByVal firstName As String, _     ByVal lastName As String, _     ByVal emailAddress As String) As Integer _      Implements ICustomer.RegisterCustomer  Throw New NotSupportedException()  End Function     Public Sub  UnregisterCustomer  (ByVal id As Integer) _     Implements ICustomer.UnregisterCustomer  Throw New NotSupportedException()  End Sub     Public Sub  ChangeEmailAddress  (_      ByVal id As Integer, ByVal emailAddress As String) _      Implements ICustomer.ChangeEmailAddress  Throw New NotSupportedException()  End Sub     Public Function  GetCustomer  (ByVal id As Integer) _      As ArrayList Implements ICustomer.GetCustomer  Throw New NotSupportedException()  End Function End Class 

For Web services, you use the SOAPSUDS tool to extract the metadata from the service, and then generate an assembly that has the required metadata. You can then build a proxy DLL and have the client program refer to it. This is conceptually equivalent to the first approach. The server, of course, has to reference the real object's assembly.

Unlike the COM model, there is no reference counting, interface negotiation, building and registering separate proxies and stubs, worrying about global identifiers, or use of the registry. Because of metadata, all you have to do is inherit from MarshalByRefObject to make an object remotable.

Remoting Configuration Files

You use configuration files to define where the object is activated. The client can then use the New operator to create the object. The big advantage in doing this is that as the object location changes (such as a URL or TCP channel), or the formatter you want to use changes, the client does not have to be modified or rebuilt.

Multiple classes can be configured on the client. Configuration files are loaded into the client using the RemotingConfiguration.Configure method.


Team-Fly    
Top
 


Application Development Using Visual BasicR and .NET
Application Development Using Visual BasicR and .NET
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 190

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