- Implementing a Remote Server
- Defining Shared Code
- Handling Server Events on the Client
- Multithreading Caution
- Summary
Handling Server Events on the Client
Again, synthesizing the client to its bare elements, we need to reference the shared assembly defined in the preceding part, create an instance of the shared client class, and invoke a remote behavior. We also need to define the client's app.config file. This app.config file is part of the client's solution, not the shared code's solution. Listing 4 contains the client code and Listing 5 contains the client's app.config XML.
Listing 4 Simplified Client Code
using System; namespace Client { class Class1 { [STAThread] static void Main(string[] args) { General.Client client = new General.Client(); client.RaiseRemoteEvent(); Console.WriteLine("press [enter] to quit"); Console.ReadLine(); } } }
Listing 5 Contents of the Client Assembly's app.config File
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.runtime.remoting> <application> <channels> <channel ref="http" port="0"> <clientProviders> <formatter ref="binary" /> </clientProviders> <serverProviders> <formatter ref="binary" typeFilterLevel="Full" /> </serverProviders> </channel> </channels> <client> <wellknown type="General.Shared, General" url="http://localhost:9999/Shared.soap" /> </client> </application> </system.runtime.remoting> <appSettings> <add key="user" value="Your Name Here!" /> <add key="echo" value="true" /> </appSettings> </configuration>
Referring to Listing 5, the client's app.config file contains similar elements to the server's app.config file. By setting the port to 0, however, we permit Remoting to manage the client's port; and in the <wellknown> section we specify the URL of the server, including the hostname, the server's port, and the URI we specified in the server configuration.
When we're finished defining the code, we have three assemblies. We have the shared code assembly that's referenced by both the client and server console applications.
Run the server first, and if you step through the client's code when the Shared object is created in the General.Client constructor you should see (using QuickWatch) that the instance of the General.Shared class is a proxy reference to the server's object, as shown in Figure 1.
Figure 1 We know by the contents of the QuickWatch window that we have a reference to a proxy object, called __TransparentProxy.
From our perspective, we can treat the remote proxy object like a local object because the transparent proxy manages marshaling the messages between client and server. It's important to note, though, that a Singleton object's state could be changed by other clients, and a SingleCall server behaves like a web application; that is, SingleCall servers are stateless.