This is the final part of a three-part demo application dubbed Networked Financial System. The first article includes the fundamentals of building the server and the windows-client. The second part has addressed some of the issues involved in building and designing application oriented ASP server controls. In this article we will look at a simple example that demonstrates how one can go about to build a web client to accesses the server.
To successfully build and run the code of the sample web-client, attached with this article, we need the source code or compiled assemblies of the first and second articles. For the benefit of those who havent got a chance to look the last two articles but stumbled on this, I have included the source code of the last two articles. It is located in folder \NeFsDemoPartThree\NeFsUpdate. Consult the simple read me file (Document\NeFsReadME.txt) to build and run the NeFsServer assembly.
Building the Web-Client
The main issues involved in building and connecting the web-client to the severe are briefly discussed below.
Generating the Client Proxy
Use the soapsuds utility shipped with .NET visual studio to generate the client proxy. Note that if the server was based on web-services we use the wsdl utility to generate the client proxy. You can either generate a C# class based client proxy or generate assembly-based proxy. Both work fine so long as we include or reference them in the project appropriately. To generate class or assembly based client proxy first run the NeFsServer and then use either of the following commands from the appropriate path in the command window (use the Visual Studio command prompt that includes the relevant environment variables so that you can run the utility from any path you want):
Soapsuds url :http://localhost:8000/NefsSystem/NeFsRemoteObject.soap?wsdl oa: NeFsRemoteObject.dll ; or
Soapsuds url :http://localhost:8000/NefsSystem/NeFsRemoteObject.soap?wsdl gc
The client proxy class or assembly is a transparent proxy. It looks like the remote object with the same public methods. The transparent proxy uses the real proxy to create messages from method calls using invoke() method (See documentation for detail). An excerpt from the client proxy class is listed in Listing 1 below:
Listing 1: An excerpt from the Client Proxy Class
public class NeFsRemoteObject : System.Runtime.Remoting.Services.RemotingClientProxy,
public Object RemotingReference
Modifying the Web.Config File
Strictly speaking the web-client is a middle tier server that serves as a server to the end client and in turn is a client to the NeFsServer. (See Figure 1 below) Therefore we still require some of the client side configuration settings included in the Windows Client configuration file. The key store manager is no longer relevant as the end user is not responsible for managing the public/private security key and the Url of the remote NeFs server. However, we still need to add these settings either in the web configuration file manually or provide some sort of manager as we did for the window client. Here I simply included them in the web.config file under custom section setting.
The other configuration settings required are the channel and client provider settings (we could use either soap or binary formatters. Since we know that our end client is .NET based. In practice restricting the provider to Http and the formatter to soap enables the server to connect to other technologies such as CORBA and JAVA.)
Figure 1: The relationship between the end client, the web client and NeFs server
The configuration setting included in the Web.Config file is reproduced below.
Listing 2: Configuration Settings
<section name ="NeFsRunTimeParams"
<NeFsRunTimeParams NavigatingUrl =http://localhost:8000/NefsSystem/NeFsRemoteObject.soap
DbConnection ="Data Source=(local);Initial catalog=TradeDB;User Id = sa ; Password=;"/>
<channel type="System.Runtime.Remoting.Channels.Http.HttpChannel, System.Runtime.Remoting, Version=1.0.3300.0, Culture=neutral,
<provider type="System.Runtime.Remoting.Channels.SoapClientFormatterSinkProvider, System.Runtime.Remoting, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<provider TraceFile ="ClientFormatterTrace.txt"
type ="NefsSystem.Remoting.MessageFormatter.NeFsClientFormatterSinkProvider,NeFsRemoting"/> <provider PubKeyStorage ="KeyStore.xml"
type ="NefsSystem.Remoting.SecuredChannel.NefsClientChannelSinkProvider,NeFsRemoting"/> </clientProviders>
Note that unlike the windows client, the settings for SingleTagSectionHandler include the assembly reference (System). This is because here the default assembly is System.Web, and leaving out the assembly reference forces the system to look for the SingleTagSectionHandler class in the System.Web.dll instead of System.dll and returns an exception since the class is not included in the System.Web.dll. (I found it a bit difficult to run the web client without including the System.dll in the local web-client debug folder. Under normal circumstances I would expect the system to look in the global assembly cache, as it is a shared assembly. I am not sure why it is not working, as it should.)
Except the <configuration> and <NeFsRunTimeParams > settings all the other settings are the same as in the windows client configuration settings.
Connecting the Web-Client to the server
There are different ways of building the web-client both in terms of the overall design and the way the infrastructure is put together to access the server. Without loss of generality here I will simply put together a simple sample demo and avoid digressing from the underlying object of the whole exercise.
The server is connected using a command button (cmdConnect) found on the main page of the web-client (MainForm.aspx). The connection code is the same us what we have in windows client. The code is listed in Listing 3 below:
Listing 3: Code for connecting to the server
IDictionary configAttributes = (IDictionary)ConfigurationSettings.GetConfig("NeFsRunTimeParams");
string remoteUri = (string)configAttributes["NavigatingUrl"];
string dbConnection = (string)configAttributes["DbConnection"];
Using ConfigurationSettings.GetConfig method we get the values of the configuration settings and store it in a dictionary. Here we have only two settings for the remote Url and database connection string. Note that we could have as many settings as we would like based on the requirements of the web-client that we build.
Using the System.Activators GetObject static method we instantiate the object and pass it to the NefsSystem.ClientDataComponent.NeFsDataLink object to be used by the remaining pages of the web-client. Note that instead of using the Activator class it is also possible to use either the new operator or the static method Connect() of the class RemotingServices for well-known object. (Consult documentation for detail)
In this sample we used only the Monte-Carlo simulation service provided by the server. Since this does not require the database we are not using the connection string to connect to the database as we did in the windows client.
The SimulationInputWindow.aspx page implements the simulation routines. Using the instance of the remote object we simply pass the required inputs to the Simulate method and obtain the results from the CallContext that set properties carried with the execution path. See Listing 4 below:
Listing 4: Running the Simulation
//run the simulation note that the parameters
//Get the results from the Call context object
DataSet __dsSimResult = null;
SimulatedValues __SimValues = null;
__SimValues =(SimulatedValues)CallContext.GetData("SimulationResults"); //get the object the values of the simulation
__dsSimResult=__SimValues.SimulationValues; //get the dataset
double MeanPayOff = __SimValues.MeanPayOff; //get the mean payoff
double DiscountedPayOff = __SimValues.DiscountedMeanPayOff;//get the discounted payoff
ColumnInformation  colInof = __SimValues.ColumnInfo; //get the column info attributes
We pass the results to the simulation display page (SimulationResults.aspx) using Server.Transfer() method.
Note how we used the sever controls that we developed in part II of this demo. In particular the text boxes used as data capture interface in the SimulationInputWindow.aspx page show how one can use the instances of these controls for different data types with different culture settings.
Similarly we used the grid control to display the simulation results with scrolling facility so that clients can easily scroll through the result both vertically and horizontally.
Running the example
- Unzip the attached zip file. The server code is included in \NeFsDemoPartThree\ NeFsUpdate folder. Build the server following the brief guide included in the Document\NeFsReadME.txt file.
- Create a virtual directory to connect to the localhost. If you load the solution in NeFsWebClient this will load for you all the remaining five projects.
- Compile the source code of both the server and the ASP.Server controls.
- Run the NefsServer.
- Make sure you have referenced all the required assemblies in the example project (NeFsWebControlsExample). These are:
- NeFs Related assemblies: NeFsClientDataAccessComponent.dll, NefsRemoting.dll, NeFsSerializableLogicalObjects, NeFsWebControls.dll, NeFsWebDataGrid.dll, NeFsWebDropDownBox.dll, NeFsWebGridDataSuppor.dll, and NeFsWebTextBox.dll.
- .NET related assemblies: System.dll (note you need to move this dll to local folder if you run into a problem.),
- System.Data.dll, System.Configuration.Install.dll, System.Data.dll, System.Design.dll, System.Drawing.dll, System.Runtime.Remoting.dll, System.Runtime.Serialization.Formatters.Soap.dll, System.Web.dll, System.Web.Services.dll, System.Windows.Forms.dll, and System.Xml.dll.
- While the server is running, use the Debug start new instance menu of .NET VS to instantiate the NeFsWebControlsExample assembly of the web-client.
In the last three articles I have attempted to provide the possible ways that one can use the new C# and .NET framework to develop three-tier client-server based application. We have seen how the various components of the new development tools can be used to come up with a system that could easily be ran either over the Internet or using windows based traditional clients. Obviously, the demo application has only scratched the bare minimum functionality that C# and the .NET framework provide. Though both the architecture of the demo and the logic behind the code are not production quality, it serves as a starting point or provides an hands-on opportunity for those new comers to the C# and .Net community.