.NET Remoting and Event Handling in VB .NET, Part 2, Page 2
It is a bit more advanced than a basic sample because it uses some patterns (Command, Factory, Singleton, and Observer) that you might use in a real application, as opposed to just the bare minimum code you would need to connect to the remote server.
The Client class' Sub New configures the client application, creates an instance of the remote server, and connects the Client.OnMessageEvent to the remote server object, Chatter. The code never creates an instance of the Client object directly. (Note that the constructor Sub New is private.) Instead, it uses the Singleton pattern and the Client object indirectly through the read only property, Instance. Finally, the Send and OnMessageEvent event handlers handle the connection to and from the server (as discussed in the previous section.)
Implement the Presentation Code
The objective here doesn't involve Windows Forms or Web Forms; it is about .NET remoting and server events. Consequently, you can use any kind of GUI to test your solution, and that's what the example does—with a twist.
By separating your pieces and using good patterns, you can loosen the relationship between presentation, middleware, and server. You will see this in the implementation of the Console application.
Because the console application hardly mentions—and only indirectly uses—the .NET remoting solution, the client could be practically anything (see Listing 5).
Listing 5: The Presentation Layer Is a Console Application, but Good OOP Means It Could Have Been Anything
Imports SharedCode Imports Softconcepts.ApplicationBlocks.RadioPattern Class ClientApp Implements IListener Public Shared Sub Main() With New ClientApp .Run() End With End Sub Public Sub Run() Broadcaster.Add(Me) ProcessCommand("Startup") While (True) Console.Write("chat>") If (ProcessCommand(Console.ReadLine()) = False) _ Then Exit While End While ProcessCommand("Shutdown") Broadcaster.Remove(Me) End Sub Public Shared Function ProcessCommand(ByVal input As String) _ As Boolean Return CommandFactory.Create(input).Execute(input) End Function Public Overloads Sub Listen(ByVal message As String) _ Implements IListener.Listen Console.WriteLine(message) End Sub Public ReadOnly Property Listening() As Boolean _ Implements IListener.Listening Get Return True End Get End Property Public Overloads Sub Listen(ByVal message As String, _ ByVal formatter As Softconcepts.ApplicationBlocks.RadioPattern.IFormatter) _ Implements Softconcepts.ApplicationBlocks.RadioPattern.IListener.Listen If (message.Equals("chat>")) Then Console.Write(message) Else Console.WriteLine(formatter.ApplyFormatting(message)) End If End Sub End Class
The Sub Main is the entry point for the presentation layer. It is simply an instance of the contain class and a call to a single method, Run. This is pretty good encapsulation.
Except for the Imports statement, the listing makes no reference to the middle layer—Client class—or any of the remoting plumbing. This means you could strip off this presentation layer and easily put a WinForms GUI or something else on top of it.
The basic behavior is that the run method loops while there are commands to process, period. Key concepts that make this possible are grounded in patterns. Part 3 will explore all of the patterns used for this solution.
What Have You Learned?
Part 2 demonstrated how to implement the client's App.config file, so that the client could talk to the server. It also discussed why clients that handle server events have to be remotable. Because the .NET plumbing handles this for you, you really only needed to make your remotable client object inherit from MarhsalByRefObject and share that code between client and server.
All of the extra code really demonstrates the use of some very powerful design patterns. While you wait for Part 3 of this three-part installment, see if you can spot the Command, Factory, Singleton, and Observer patterns used.
Part 3 will describe and explain the implementation of the patterns, introduce internationalization in the context of this sample, and point out where code that is too OOPY can cause goofy behavior. (For fun, write me if you find the goofy behavior.)
About the Author
Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his book Visual Basic .NET Power Coding from Addison-Wesley and his upcoming book UML DeMystified from McGraw-Hill/Osborne (Spring 2005). Paul is also the founder and chief architect for Software Conceptions, Inc, founded 1990. He is available to help design and build software worldwide. You may contact him for consulting opportunities or technology questions at email@example.com.
If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org.
Copyright © 2005 by Paul Kimmel . All Rights Reserved.