As you learn about Event and Delegates in
Remoting using VB.NET in my previous article, now you will see the
remaining part:The server creates an HttpChannel to send and receive messages. It registers
both server-activated and client-activated SimpleObjects and waits for a client
to call a method on the remote object. (See Listing 25.15.)
Listing 25.15: EventServer.vb
Imports
System.Runtime.Remoting
Imports
System.Runtime.Remoting.Channels
Imports
System.Runtime.Remoting.Channels.Http
Imports
SimpleEventLib
Namespace
EventServer
Class ServerEvent
Private
Shared Sub Main(ByVal
args As String())
Dim http
As HttpChannel = Nothing
http = New HttpChannel(1234)
ChannelServices.RegisterChannel(http)
RemotingConfiguration.RegisterWellKnownServiceType(GetType(SimpleObject),
"Simple",
WellKnownObjectMode.Singleton)
RemotingConfiguration.ApplicationName =
"Simple"
RemotingConfiguration.RegisterActivatedServiceType(GetType(SimpleObject))
Console.WriteLine("Press <enter> to
exit.")
Console.ReadLine()
End Sub
End Class
End Namespace
Notice that the server-activated registration uses Singleton mode. There is no
registration of the SyncRemoteEvent object. Running the server executable
produces the output in Figure 25.10, while Figure 25.11 displays the client's
output.
Figure 25.10: EventServer

Figure 25.11: EventClient Output

Listing 25.16: EventClient.vb
Class
ClientEvent
Public Sub New()
Console.WriteLine("In ClientEvent
constructor")
End Sub
Private Shared Function Main(ByVal
args As String())
As Integer
Dim client
As SyncRemoteEvent =
Nothing
Dim http
As HttpChannel =
Nothing
http = New HttpChannel(2345)
ChannelServices.RegisterChannel(http)
'client = (SyncRemoteEvent)ClientEvent.InitClientEvent();
client = New SyncRemoteEvent()
Dim simple As
SimpleObject = Nothing
simple = DirectCast(Activator.GetObject(GetType(SimpleObject),
"http://localhost:1234/Simple"),
SimpleObject)
simple.RemoteEvent += New
RemoteEventHandler(client.EventHandler)
Dim ret As String = Nothing
ret = simple.ConCatString("using",
"Activator.GetObject")
Console.WriteLine(ret)
simple.RemoteEvent -= New
RemoteEventHandler(client.EventHandler)
ret = simple.ConCatString("2 using",
"Activator.GetObject")
Console.WriteLine(ret)
Return (0)
End Function
End Class
The client creates a channel, but in this instance it specifies a port number
(see Listing 25.16). The server must have a defined port number to contact the
client during the event firing. The event handler is created with a simple new;
no registration is required. The line commented out above the new operator will
be discussed later. SimpleObject is a server-activated object because of the
Activator.GetObject(). The code for a client-activated remote object could be
Activator.CreateInstance() or as follows:
RemotingConfiguration.RegisterActivatedClientType(GetType(SimpleObject),
"http://localhost:1234/Simple")
simple = New
SimpleObject()
The client then subscribes to the event and calls SimpleObject.ConcatString() it then unsubscribes and makes a subsequent call to ConcatString().
While experimenting with remote events, we made an interesting discovery. As the
code stands now, the event is fired from within the server's application domain
to the client's. The client doesn't actually intercept the event unless the
server has some reference to it. If, for example, ClientEvent was derived from
SyncRemoteEvent, an exception would be thrown when it is registered with
SimpleObject's event delegate-that is, unless the remoting framework is tricked
into thinking it is dealing with a SyncRemoteEvent rather than a ClientEvent
object. Deceiving the framework results in output such as that shown in Figure
25.12.
Figure 25.12: Event Client Output

Listing 25.17: EventClient.cs
Class
ClientEvent
Inherits SyncRemoteEvent
Public Sub New()
MyBase.New()
Console.WriteLine("In ClientEvent
constructor")
End Sub
Private
Shared Function InitClientEvent()
As Object
Dim client
As SyncRemoteEvent =
Nothing
RemotingConfiguration.RegisterWellKnownServiceType(GetType(ClientEvent),
"Event",
WellKnownObjectMode.SingleCall)
client = DirectCast(Activator.GetObject(GetType(SyncRemoteEvent),
"http://localhost:2345/Event"),
SyncRemoteEvent)
Return
DirectCast(client, Object)
End Function
Public
Overrides Sub EventHandler(ByVal
sender As Object,
ByVal args As
RemoteArgs)
Console.WriteLine()
Console.WriteLine("In
ClientEvent.EventHandler")
Console.WriteLine("Machine:{0} Dir:{1}",
args.MachineName, args.CurrentDir)
Console.WriteLine()
MyBase.EventHandler(sender, args)
End Sub
End Class
The first step in accomplishing direct event interception is to make the
EventHandler() in SyncRemoteEvent a virtual method. Then, override the method in
ClientEvent. Duping the framework takes place in the static method
InitClientEvent(). Register the server-activated object as a type of ClientEvent
in either SingleCall or Singleton mode. Then, Activator.GetObject() returns a
transparent proxy of the requested type, SyncRemoteEvent. If you look at the
output, a ClientEvent instance is created, but the proxy has been downcast to a
SyncRemoteEvent instance. The result is that the server doesn't have any
reference to ClientEvent. No exception is thrown during registration with the
event delegate. Because the EventHandler() is virtual, the proper method is
called. Experimenting with this as a client-activated object resulted in
failure, no matter what twists and contortions were taken.
Conclusion
HTML clipboard
Hope this article would have helped you in understanding ServerEvents and
ClientEvent in Remoting using VB.NET.