ADO.NET
Building a Distributed Component Client using C# and .NET

Gopalan Suresh Raj

Note
To work with any of these samples, you will need the following:
.........................................Microsoft .NET SDK
.........................................Microsoft Visual Studio.NET Beta 2 or higher

 

1. Develop the KeeperClient.cs Application

Create a regular C# client application.

Our objective as a Client to a Distributed Component Server is to activate the remote object. We need to use the types in the System.Runtime.Remoting and System.Runtime.Remoting.Channels.Tcp namespaces, as we need to use the TCP Channel. So we use these as shown in Lines 21 and 22. The Client does not need to derive from anything as it's not a server-side entity that needs to have a distributed identity. As we're developing a client application, we don't need to specify a client port when we instantiate a TcpChannel on Line 51. The most important part of this application is object activation that is shown on Line 53. To invoke remote methods, you have to first activate the remote object and obtain a reference to the associated proxy object on the client side. As shown on Line 53, to activate the object and retrieve a reference to the associated proxy object, you can call the GetObject() method of the Activator class. When doing so, you have to also pass along the remote class name, and its fully qualified location, including the complete URI. Once this is done, you can invoke methods on this object as shown on Lines 73 and 84.

Client.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
//////////////////////////////////////////////////////
/// The following example illustrates a Client to a
/// Distributed component developed using C# and .NET.
///
/// author: Gopalan Suresh Raj
/// Copyright (c), 2001-2002. All Rights Reserved.
/// URL: http://gsraj.tripod.com/
/// email: gopalan@gmx.net
///
/// <compile>
/// csc /r:BookKeeper.exe /t:exe /out:KeeperClient.exe KeeperClient.cs
/// </compile>

/// <run>
/// KeeperClient create Checking "Athul Raj" 10000
/// KeeperClient delete 1
/// </run>
/////////////////////////////////////////////////////////
using System;
// Include Remoting API functionality
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace BookKeeper {
  /// <summary>
  /// The KeeperClient class.
  /// </summary>
  public class KeeperClient {

    /// <summary>
    /// Static Entry Point to the Application
    /// </summary>
    /// <param name="args"></param>
    /// <returns></returns>
    public static int Main (String[] args) {
      int argLength = args.Length;
      if ( argLength < 2) {
        Console.WriteLine ("Usage: KeeperClient <create|delete> <accountNumber|Checking|Savings> <customerName> <startingBalance>");
        return -1;
      }

      string operation = "", type = "";
      string []customerNames = new String [1];
      int accountNumber = 0;
      float startingBalance = 0;

      AccountKey key = new AccountKey ();

      try {
        // Get a reference to the remote Distributed Component
        TcpChannel channel =
new TcpChannel ();
        ChannelServices.RegisterChannel (channel);
        BookKeeper keeper = (BookKeeper) Activator.GetObject (
typeof( BookKeeper ),
                                                              
                                  "tcp://127.0.0.1:1099/BookKeeper");
        Console.WriteLine ("Obtained a reference to the Server Object...");

        operation = args [0];

        if (argLength > 2) {
          type = args [1];
          // This can be a create operation
          if (operation.Trim().ToLower() == "create") {
            if (type.Trim().ToLower() == "checking") {
              key.Type = AccountType.CheckingAccount;      
            }
            if (type.Trim().ToLower() == "savings") {
              key.Type = AccountType.SavingsAccount;
            }
            customerNames[0] = args[2];
            startingBalance = (float)System.Double.Parse (args[3]);
            Console.WriteLine ("Invoking createAccount() now ...");
            // Invoke operations on the Distributed Component
            key = keeper.createAccount (key.Type, customerNames, startingBalance);
            Console.WriteLine ("Key of new Row is: {0}", key.Key);
          }
        }
        else {
          // This can be a delete operation
          if (operation.Trim().ToLower() == "delete") {
            accountNumber = System.Int32.Parse (args[1]);
            key.Key = accountNumber;
            Console.WriteLine ("Invoking deleteAccount() now ...");
            // Invoke operations on the Distributed Component
            bool result = keeper.deleteAccount (key);
          }
        }
        // Dispose of the object
        keeper = null;
      }
      catch (Exception exception) {
        Console.WriteLine (exception.ToString());
      }
      return 0;
    }
  }
}

 

2. Build the Application

Build the files that make up the Client.

Command Prompt
C:\MyProjects\Cornucopia\COMplus\BankServer\BookKeeper\bin\Debug>csc /r:BookKeeper.exe /t:exe /out:KeeperClient.exe KeeperClient.cs
Microsoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914]
Copyright (C) Microsoft Corp 2000-2001. All rights reserved.


C:\MyProjects\Cornucopia\COMplus\BankServer\BookKeeper\bin\Debug>

Ignore the warning about the assembly being a satellite assembly.

3. Run the Client

Make sure the Distributed Component Server is up and running before firing-up the client.

Note:
There is an inherent and 'intentional bug' in the way deletes are handled in the BookKeeper Server. You can only delete records in the order that they were created - i.e., you'd have to delete the latest record first !!! If you do try to delete in any other order, you will not be able to create the next new Account !!! This is because of the way new Primary Keys are generated. For explanation, please look at the
BookKeeper::getNextKey() method. I intentionally introduced this bug in the program to demonstrate that even though ADO.NET's DataSet is physically disconnected from the DataBase, it maintains and manages its data internally,  and  still checks Constraints and behaves very much like a regular database.
 

 

Command Prompt
C:\MyProjects\Cornucopia\COMplus\BankServer\BookKeeper\bin\Debug>KeeperClient create Checking "Athul Raj" 100000
Obtained a reference to the Server Object...
Invoking createAccount() now ...
Key of new Row is: 6

C:\MyProjects\Cornucopia\COMplus\BankServer\BookKeeper\bin\Debug>
KeeperClient delete 6
Obtained a reference to the Server Object...
Invoking deleteAccount() now ...

C:\MyProjects\Cornucopia\COMplus\BankServer\BookKeeper\bin\Debug>

 

 

 

Channels and .NET Remoting
Building a Distributed Component Server using C# and .NET
Building a Distributed Component Client using C# and .NET

 

Download the entire source code as a zip file.

 

click here to go to
My Advanced C#/.NET Tutorial Page...

About the Author...
Gopalan Suresh Raj is a Software Architect, Developer and an active Author. He has co-authored a number of books including "Professional JMS", "Enterprise Java Computing-Applications and Architecture" and "The Awesome Power of JavaBeans". His expertise spans enterprise component architectures and distributed object computing. Visit him at his Web Cornucopia site (http://gsraj.tripod.com/) or mail him at gopalan@gmx.net.

 


Go to the Component Engineering Cornucopia page

This site was developed and is maintained by Gopalan Suresh Raj

This page has been visited times since January 01, 2002.

Last Updated : Jan 01, '02

If you have any questions, comments, or problems regarding this site, please write to me I would love to hear from you.


Copyright (c) 1997-2002, Gopalan Suresh Raj - All rights reserved. Terms of use.

All products and companies mentioned at this site are trademarks of their respective owners.