Remoting

I l @ ve RuBoard

.NET Remoting is an extremely flexible interapplication communication technology provided by the .NET Framework. It provides a tightly coupled communication model that also supports connecting to distributed systems. One major difference between remoting and Web services is that you can pass objects by reference to the target of a remoting call, which enables the target to actively communicate back to the originator of the call. This known as bidirectional communication . Remoting provides several specific features:

  • The flexibility to publish or consume services in any type of application, including console and Windows applications, Web applications (hosted in IIS), XML Web services, and Windows services

  • The preservation of type fidelity (tightly coupled)

  • The ability to pass objects and return objects by reference (bidirectional communication)

  • The implementation and use of custom communication channels or protocols

  • The customization of the communication process to provide additional functionality

The general concept behind remoting is you have the client and a service. The service registers types to be available to clients. Clients register types in order to be able to bind to types provided by the service. Type registration applies only to an application instance; to host a remoting service, you must have a process. You then have two choices: create your own process (application or service) to host your remoting service, or host your remoting service in IIS (more on this later).

The client and service do not need to be on separate machines. Remoting can be used in a distributed environment, but it is a generic interprocess communication technology. Much like the DCOM technologies it replaces , remoting lets you create and invoke remote objects and marshal data, objects, and references.

Remoting is most useful for communication between machines on the same network. It is not really intended as an Internet communication technology. For that purpose, Microsoft recommends XML Web services.

Getting Started

The key to providing a class through remoting is the RemotingConfiguration class. This class provides all of the necessary methods to configure and monitor the remoting services provided and consumed by a process. Table 5-1 lists the properties supported by this class that provide information specific to the current application and process.

Table 5-1. Public Shared Properties of the RemotingConfiguration Class

Property

Description

ApplicationId

Gets the ID of the currently executing application

ApplicationName

Gets or sets the name of a remoting application

ProcessId

Gets the ID of the currently executing process

The methods that control the registration of service and client types are listed in Table 5-2. These methods give a process control over how services provided by that application behave. In addition to the ability to register types, you can also find out whether a type has been registered, which types have been registered (for both service and client), and which types have been activated on the client.

Table 5-2. Public Shared Methods of the RemotingConfiguration Class

Method

Description

Configure

Reads the configuration file and configures the remoting infrastructure

GetRegisteredActivatedClientTypes

Retrieves an array of object types registered on the client as types that will be activated remotely

GetRegisteredActivatedServiceTypes

Retrieves an array of object types registered on the service end that can be activated on request from a client

GetRegisteredWellKnownClientTypes

Retrieves an array of object types registered on the client end as well-known types

GetRegisteredWellKnownServiceTypes

Retrieves an array of object types registered on the service end as well-known types

IsActivationAllowed

Returns a Boolean value indicating whether the specified type is allowed to be client-activated

IsRemotelyActivatedClientType

Checks whether the specified object type is registered as a remotely activated client type

IsWellKnownClientType

Checks whether the specified object type is registered as a well-known client type

RegisterActivatedClientType

Registers an object type on the client end as a type that can be activated on the server

RegisterActivatedServiceType

Registers an object type on the service end as one that can be activated on request from a client

RegisterWellKnownClientType

Registers an object type on the client end as a well-known type (single call or singleton)

RegisterWellKnownServiceType

Registers an object Type on the service end as a well-known type (single call or singleton)

To have an application host a service through remoting, you must do the following:

  1. Create a type that you want to make available as a service.

  2. Create a communication channel ( TcpChannel or HttpChannel ).

  3. Register your type as a Service type, using the RegisterActivated ­ServiceType or RegisterWellKnownServiceType method

For a client to consume a service through remoting, the following must happen:

  1. The client must have a reference to the type to be remoted .

  2. Register the type as a client type (using the RegisterActivatedClientType or RegisterWellKnownClientType method), specifying the host name of the service, the channel used, and the desired port. The client registration method you call must match the corresponding server registration method for this to work.

  3. Create, or otherwise obtain, an instance of the registered type.

Remoting Activation Models

Two activation models are supported by remoting: activated and well-known. The activated model causes a new instance of a remoted class to be created in the service process when a client creates an instance of the type. The client can then make multiple calls to the remote class, all to the same class instance.

The well-known activation model is quite different. Essentially , the service publisher has a choice: have a new class instance created for each method invocation from a client or make the class available as a singleton to all remoting clients.

Picking the Right Channel

Remoting offers a performance advantage over XML Web services because it provides a choice of communication channels. The two channel classes provided with the .NET Framework are TcpChannel and HttpChannel .

The TcpChannel Class

TcpChannel offers by far the best performance. In an intranet scenario, where security is not an issue, this is the best-performing option. A remoting call through TcpChannel is generally five to seven times faster than an equivalent call through HttpChannel .

You cannot use TcpChannel when a remote object is hosted in IIS, so TcpChannel is a remoting-only solution. You must create your own process to host objects with TcpChannel .

The HttpChannel Class

HttpChannel has benefits as well. The overhead for a remoting call through HttpChannel is greater than that for TcpChannel , but if you host the remote object in IIS (a requirement if you are using HttpChannel ), you gain a whole host of scalability benefits. In other words, by hosting your remote objects in IIS, you can take advantage of features such as clustering, robust scaling, session state, and farming.

Sometimes you'll have to use HttpChannel , which is less efficient than TcpChannel . To make things less painful, you can force the use of binary encoding for all object marshaling instead of the default marshaling.

Marshaling Data

When you pass parameters to or receive values from remote methods, you're marshaling data (in much the same way that Web services work). The important twist for remoting is the ability to pass variables by value or, more significantly, by reference. The default, as for Visual Basic .NET in general, is to marshal all of your parameters and return types by value.

Marshaling Types By Value

The fact that the default marshaling of types is by value is not a major problem. In fact, you don't even need to think twice about it when you're using standard types that support serialization. If, on the other hand, you want to marshal a custom type, you must implement a form of serialization (as described earlier).

Marshaling Types By Reference

If you want a class to be passed by reference instead of by value, you must take a different approach. A class that supports by reference marshaling through remoting must derive from the MarshalByRef class. This class provides all of the functionality required to allow manipulation of a remote object. Objects that are marshaled by reference can support remote events and calls to methods and properties. This is pretty slick, and you get it virtually for free just by deriving a class from MarshalByRef .

To support having a service call a method on a client object passed by reference, the client must also register a communications channel. Otherwise, any method invocation on the passed object will fail. (The client would essentially not be listening for a request.)

Caution

Bidirectional communication using pass-by-reference is a great feature but generally should not be used in a distributed application environment. The overhead of calling back to the client just to get the value of properties is a complete waste of resources. You're better off serializing the data. Pass-by-reference is most useful when you want remote systems to be able to trigger events or perform some other specific operation.


Using a Separate Interface

You have a choice when designing your remoting implementation. You can remote a class and provide the client with a copy of that class ”you need a reference to the type you want to consume, after all ”or you can provide a reference to an interface supported by your remote class. Which one do you choose? Of course, it depends.

Remoting an interface instead of a class has certain advantages. You can put the interface into a separate assembly from the class that implements it. Designing in this manner allows the publisher to distribute an assembly that allows clients to talk to their remoting objects, without publishing any real code. If you were to remote a class, you'd have to provide all clients with a definition of that class (or at least a base class). Unfortunately, that class would contain all of the implementation code for the remoted class.

It is often desirable to have the client application be completely unaware of the implementation details of your remoted object. By using an interface (that's available, say, in a separate assembly, as shown in Figure 5-3), you can allow the client to consume a service, without providing any of the implementation details.

Figure 5-3. Using a common interface to hide implementation details.

graphics/f05pn03.jpg

Remember that if you ship out an assembly containing a remoted class, any customer can run ILDASM on the assembly (or one of the other reverse-engineering tools) and extract the implementation code. If you distribute only an interface, there's nothing to reverse-engineer .

Remoting Singletons

You've seen a remoting method that results in new object instances being created on the server for each incoming client request. This is not always desirable. Sometimes you might want to allow only a single object to exist ”a singleton.

Remoting an object as a singleton is fairly simple. In the same way that we registered other types through remoting, we can also register singletons. Unlike with true singletons, you must define your class with a public constructor because the remoting infrastructure is responsible for creating and maintaining the singleton throughout its lifetime and will only allow a single instance of the class to be created through the remoting channel.

The only thing you really need to worry about is when your singleton is targeted for garbage collection. That's where lifetime leases come into play.

Lifetime Leases

When you define a singleton for remoting, you must carefully consider how the object is going to be used. More specifically , you need to know whether it is acceptable for the singleton object to be recycled ( garbage-collected and then re-created) even if there are connected clients. Every remote object has a lifetime lease. A singleton can, and most likely will, exceed the default lifetime lease and be destroyed . This is not normally desirable behavior for a singleton ”it should last the entire lifetime of the application. If you don't want to deal with this, you must change the default lifetime lease to something more appropriate. In this case, an infinite lifetime lease.

Creating a infinite lifetime lease is simple and straightforward. The MarshalByRef class defines a method called InitializeLifetimeService for retrieving the lifetime service object that controls the lifetime of the current class's instance. By overriding InitializeLifetimeService , you can provide and control your own lease information. The simplest case, returning a reference to Nothing , results in a remoting object with an infinite lifetime lease. You can thus implement a true singleton through remoting. The following example illustrates how to do this:

 PublicOverridesFunctionInitializeLifetimeService()AsObject ReturnNothing'Specifyaninfinitelifetimelease EndFunction 

That's all there is to it. You can see similar code at work in the remoting example toward the end of the chapter.

Security

Remoting itself provides no features that directly support secure communication. Instead, three general approaches are available for securing your communication: securing the communication channel itself, securing the message's content, or both. We'll look at each of these options in turn .

Note

Generally, as more security features are implemented, an application's performance will get worse . And although absolute security is a desirable goal, it is never practical technically or financially unless you bury your application in a bunker! Compromises are commonplace, and you must balance the need to provide security with the overall cost of implementing it.


Securing the Communications Channel

As you know, only two remoting channels are available out of the box: HttpChannel and TcpChannel . TcpChannel , a channel implementation over the low-level TCP protocol, does not natively provide support for secure communications. You can use TcpChannel if the network environment your application is running in supports wire-level protection (such as IPSec). Unfortunately, this is not common. It generally leaves TcpChannel as a high-speed but insecure communications channel.

Internet Protocol Security Extensions (IPSec)

IPSec is a set of security extensions to the Internet Protocolv4 (IPv4) standard. IPSec is a protocol for negotiating both encryption and authentication at the wire level. Other security protocols secure specific sockets or communication, but IPSec secures all communication between hosts. IPSec is a required part of the IPv6 standard. (Support is available in version 1.1 of the .NET Framework). To communicate via IPSec, both hosts involved must support the IPSec protocol.

The alternative, of course, is HttpChannel . Recall that remoting hosts that use HttpChannel must reside in IIS. IIS provides a lot of goodies for free (although features are rarely free where performance is concerned ), including SSL and user authentication. In fact, hosting remote objects in IIS allows you to support complex security solutions with little coding required on your part.

Securing the Message's Content

You secure a message's content by encrypting it. In Chapter 9, I'll explain how to use the .NET Framework's CryptoService providers to properly encrypt data. However, you'll need to consider some issues with this approach. First, you must manually encrypt and decrypt the contents of your messages. This requires a lot of additional work but might make sense if you're using the remoting TcpChannel . You'll take a performance hit, but probably less of one than if you use HttpChannel over SSL (as discussed in the previous section).

Ultimately, the choice is up to you. Depending on your performance requirements, you might try several different combinations just to see what fits. Remember that implementing your own security strategy is not for the faint-hearted. More often than not, you're far better off taking advantage of built-in technologies that free you from many of the implementation details. Using IIS to host your remote objects is an excellent example. The services provided by IIS ”including user authentication, secure sockets, and a scalable performance architecture ”are nothing to sniff at.

Tying It All Together

To tie together most of the topics discussed so far, I created a remoting sample that does a little bit of everything. The sample, which is simply called Remoting, does the following:

  • Registers a type as a singleton

  • Passes a custom type by value (supports serialization)

  • Passes a custom type by reference (inheriting from MarshalByRef )

  • Creates channel sinks

To start with, we'll define the following custom marshaling types in a common assembly:

 PublicClassMyClient InheritsMarshalByRefObject PublicSubPostMessage(ByValmsgAsString) MsgBox(msg) EndSub EndClass <Serializable()>PublicStructureMachineData PublicNameAsString PublicProcessIDAsInteger PublicIPAddresses()AsSystem.Net.IPAddress EndStructure 

Next, we'll define an interface, also in the shared common assembly:

 PublicInterfaceIMachine ReadOnlyPropertyName()AsString ReadOnlyPropertyProcessID()AsInteger ReadOnlyPropertyIPAddresses()AsSystem.Net.IPAddress() FunctionGetMachineData()AsMachineData SubSendMeAMessage(ByValcAsMyClient) EndInterface 

In the server application, we'll implement the IMachine interface with the Machine class. To simplify debugging and to illustrate how this works, we'll include a Console.WriteLine call in each of the methods. When you run the host application, you'll see printed statements documenting all of the remoting activities:

 ImportsRemoteInterfaces ImportsSystem.Collections ImportsSystem.Net PublicClassMachine InheritsMarshalByRefObject ImplementsIMachine PublicSubNew() MyBase.New() Console.WriteLine("Machineobjectcreated") EndSub PublicReadOnlyPropertyName()AsStringImplementsIMachine.Name Get Console.WriteLine("Machine.Namecalled") ReturnDns.GetHostName() EndGet EndProperty ReadOnlyPropertyIPAddresses()AsIPAddress()_ ImplementsIMachine.IPAddresses Get Console.WriteLine("Machine.IPAddressescalled") ReturnDns.GetHostByName(Dns.GetHostName()).AddressList EndGet EndProperty PublicReadOnlyPropertyProcessID()AsIntegerImplements_ IMachine.ProcessID Get Console.WriteLine("Machine.ProcessIDcalled") ReturnSystem.Diagnostics.Process.GetCurrentProcess.Id EndGet EndProperty PublicFunctionGetMachineData()AsMachineDataImplements_ IMachine.GetMachineData Console.WriteLine("Machine.GetMachineDatacalled") DimmdAsNewMachineData() md.Name=Dns.GetHostName() md.IPAddresses=Dns.GetHostByName(Dns.GetHostName()).AddressList md.ProcessID=System.Diagnostics.Process.GetCurrentProcess.Id Returnmd EndFunction PublicSubSendMeAMessage(ByValcAsMyClient)Implements_ IMachine.SendMeAMessage c.PostMessage("Hello") EndSub PublicOverridesFunctionInitializeLifetimeService()AsObject ReturnNothing EndFunction EndClass 

Once we've implemented the Machine class, all we need to do is register it. In this case, we want to register the class as a singleton ”because there's no need for more than one copy of the class to exist. In this case, the decision was simple. To see how the host process is set up, check out the following example:

 ImportsSystem.Runtime.Remoting ImportsSystem.Runtime.Remoting.Channels ImportsSystem.Runtime.Remoting.Channels.Tcp ImportsSystem.Runtime.Remoting.Channels.Http ModuleModule1 PublicSubMain() DimchannelAsTcpChannel channel=NewTcpChannel(8085) ChannelServices.RegisterChannel(channel) RemotingConfiguration.RegisterWellKnownServiceType(_ GetType(Machine), "Machine",WellKnownObjectMode.Singleton) Console.WriteLine("Remotingsetupcomplete") Console.ReadLine() EndSub EndModule 

We now have a host process for our remote object. (See Figure 5-4.) To enable our client, all we need to do is create a TcpChannel (because we want to support bidirectional communication ”it's not necessary on the client otherwise), register the IMachine type, and use the Activator.GetObject method to get instances of our remote object.

Figure 5-4. The remoting client example's form.

graphics/f05pn04.jpg

The implementation code for this form looks like the following:

 ImportsRemoteInterfaces ImportsSystem.Runtime.Remoting ImportsSystem.Runtime.Remoting.Channels ImportsSystem.Runtime.Remoting.Channels.Tcp PublicClassForm1 InheritsSystem.Windows.Forms.Form #Region " WindowsFormDesignergeneratedcode " PrivateSubForm1_Load(ByValsenderAsObject,_ ByValeAsSystem.EventArgs)HandlesMyBase.Load DimcAsNewTcpChannel(8086) ChannelServices.RegisterChannel(c) RemotingConfiguration.RegisterWellKnownClientType(_ GetType(IMachine),_  "tcp://localhost:8085/Machine") EndSub PrivateSubMachineButton_Click(ByValsenderAsSystem.Object,_ ByValeAsSystem.EventArgs)_ HandlesMachineButton.Click DimmAsIMachine=_ Activator.GetObject(GetType(IMachine),_  "tcp://localhost:8085/Machine") MsgBox(m.Name) EndSub PrivateSubAddressButton_Click(ByValsenderAsSystem.Object,_ ByValeAsSystem.EventArgs)_ HandlesAddressButton.Click DimmAsIMachine=_ Activator.GetObject(GetType(IMachine),_  "tcp://localhost:8085/Machine") MsgBox(m.IPAddresses) EndSub PrivateSubProcessButton_Click(ByValsenderAsSystem.Object,_ ByValeAsSystem.EventArgs)_ HandlesProcessButton.Click DimmAsIMachine=_ Activator.GetObject(GetType(IMachine),_  "tcp://localhost:8085/Machine") MsgBox(m.ProcessID) EndSub PrivateSubEverythingButton_Click(ByValsenderAsSystem.Object,_ ByValeAsSystem.EventArgs)_ HandlesEverythingButton.Click DimmAsIMachine= Activator.GetObject(GetType(IMachine),_  "tcp://localhost:8085/Machine") MsgBox(m.GetMachineData().ToString()) EndSub PrivateSubMessageButton_Click(ByValsenderAsSystem.Object,_ ByValeAsSystem.EventArgs)_ HandlesMessageButton.Click DimmAsIMachine=_ Activator.GetObject(GetType(IMachine),_  "tcp://localhost:8085/Machine") DimcAsNewMyClient() m.SendMeAMessage(c) EndSub EndClass 

More Info

To look further at the remoting technology, start with the .NET Framework SDK quick-start samples and tutorials.


I l @ ve RuBoard


Designing Enterprise Applications with Microsoft Visual Basic .NET
Designing Enterprise Applications with Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 073561721X
EAN: 2147483647
Year: 2002
Pages: 103

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