Code Organization

In the examples that I have looked at so far, I have distributed the assembly that contains the remotable types to both the client and the server. In many cases, you will not want to do this. Another approach is to expose only an ICompany interface that contains the same methods as the Company class. To do this, you remove the Company class from the SharedLibrary assembly and then add the following interface to the assembly. Therefore, the complete contents of the SharedLibrary assembly will be as follows:

1.  using System;
2.  using System.Collections;
3.  using System.Runtime.Remoting.Lifetime;
4.  namespace SharedLibrary
5.  {
6.      [Serializable]
7.      public class Employee
8.      {
9.        private int mID;
10.       private DateTime mHireDate;
11.       private string mLastName;
12.       private string mFirstName;
13.       private decimal mSalary;
14.       public Employee()
15.       {
16.         Console.WriteLine(
17.       "Called default Employee constructor");
18.       }
19.       public Employee(int aID,string aFirst,
20.         string aLast,DateTime aDate,
21.         decimal aSalary)
22.       {
23.         mID=aID;
24.         mFirstName=aFirst;
25.         mLastName=aLast;
26.         mHireDate=aDate;
27.         mSalary=aSalary;
28.         Console.WriteLine(
29.           "Called parameterized
30.           Employee constructor");
31.         Console.WriteLine(
32.           "ID={0},FirstName={1},
33.           LastName={2}",
34.           mID,mFirstName,mLastName);
35.       }
36.       public int ID
37.       {
38.         get { return mID; }
39.         set { mID=value; }
40.       }
41.       public DateTime HireDate
42.       {
43.         get { return mHireDate; }
44.         set { mHireDate=value; }
45.       }
46.       public string LastName
47.       {
48.         get { return mLastName; }
49.         set { mLastName=value; }
50.       }
51.       public string FirstName
52.       {
53.         get {
54.         Console.WriteLine(
55.       "Calling get for FirstName property");
56.           return mFirstName; }
57.         set {
58.         Console.WriteLine(
59.       "Calling set for FirstName property");
60.           mFirstName=value; }
61.       }
62.       public decimal Salary
63.       {
64.         get { return mSalary; }
65.         set { mSalary=value; }
66.       }
67.     }
68.     public interface ICompany
					69.     {
					70.       Employee CreateEmployee(int empID,
					71.         string fstName,string lstName,
					72.         decimal sal);
					73.       Employee GetEmployee(int empID);
					74.       string CompanyName
					75.       { get; set; }
					76.     }
77. }

The SharedLibrary assembly will contain 2 types: (1) an Employee, marshal by value type, and (2) an interface called ICompany. The Employee class, which is defined on lines 6 through 67, was not changed. Lines 68 through 76 declare the ICompany interface, which has CreateEmployee and GetEmployee methods and a CompanyName read/write property. I moved the Company type to the same assembly as its server executable, so it is hidden from the client.

In addition to moving the Company class to the server application's assembly, you need to change the Company class so that it implements the ICompany interface from the shared library as shown here:

1.  using System;
2.  using System.Collections;
3.  using SharedLibrary;
4.  namespace CompanyServer
5.  {
6.      public class Company :
7.        MarshalByRefObject, ICompany
8.      {
9.        public Company()
10.       {
11.         Console.WriteLine(
12.         "Company created with default name");
13.           mName="Alan's company";
14.         mEmployees=new Hashtable();
15.       }
16.       public Company(string aName)
17.       {
18.         Console.WriteLine(
19.           "Company created with name: {0}",
20.           aName);
21.         mName=aName;
22.         mEmployees=new Hashtable();
23.       }
24.       public Employee CreateEmployee(int empID,
25.         string fstName,string lstName,
26.         decimal sal)
27.       {
28.         Console.WriteLine(
29.           "Called CreateEmployee with empID={0}",
30.           empID);
31.         Employee emp=new Employee(
32.           empID,fstName,lstName,
33.           DateTime.Now,sal);
34.         mEmployees.Add(empID,emp);
35.         return emp;
36.       }
37.       public Employee GetEmployee(int empID)
38.       {
39.         Console.WriteLine(
40.            "Called GetEmployee: empID={0}",
41.            empID);
42.         if (!mEmployees.ContainsKey(empID))
43.           throw new ApplicationException(
44.           "Key: " + empID.ToString() +
45.           " does not exist.");
46.         return (Employee)mEmployees[empID];
47.       }
48.       public string CompanyName
49.       {
50.         get { return mName; }
51.         set { mName=value; }
52.       }
53.       private string mName;
54.       private Hashtable mEmployees;
55.     }
56. }

Line 3 has a using statement for the SharedLibrary namespace that contains the ICompany interface. On line 7, you can see the major change that I made to the definition of the Company class. Now, in addition to extending System.MarshalByRefObject, the Company class also implements the ICompany interface. The implementation of the CreateEmployee and GetEmployee methods and the CompanyName property on lines 24 through 52 are the same as I had before I implemented the interface. Now I need to change the server configuration file so that it looks as follows:

<configuration>
    <system.runtime.remoting>
      <application>
        <channels>
          <channel ref="http" />
        </channels>
        <client>
          <wellknown
 type="SharedLibrary.ICompany,SharedLibrary"
url="http://localhost:8080/Company.soap" />
        </client>
      </application>
    </system.runtime.remoting>
</configuration>

Notice that I changed the type attribute of the wellknown to reference the SharedLibrary.ICompany interface instead of the Company class. Finally, change the source code on the client to look as follows:

1.  using System;
2.  using System.Runtime.Remoting;
3.  using SharedLibrary;
4.  namespace CompanyClient
5.  {
6.       class Class1
7.       {
8.         [STAThread]
9.         static void Main(string[] args)
10.        {
11.          int empID;
12.          Employee emp1, emp2;
13.          RemotingConfiguration.Configure(
14.            "CompanyClient.exe.config");
15.          ICompany obj=(ICompany)
					16.               Activator.GetObject(
					17.              typeof(ICompany),
					18.               "http://localhost:8080/Company.soap");
19.          Console.WriteLine(
20.            "Enter an Employee ID");
21.          empID=int.Parse(
22.            Console.ReadLine());
23.          Console.WriteLine(
24.            "Enter a first name");
25.          string strFirstName=
26.            Console.ReadLine();
27.          Console.WriteLine(
28.            "Enter a last name");
29.          string strLastName=
30.            Console.ReadLine();
31.          emp1=obj.CreateEmployee(
32.            empID,strFirstName,
33.            strLastName,1000);
34.          Console.WriteLine(
35.           "Enter the key of an Employee to lookup");
36.          empID=int.Parse(Console.ReadLine());
37.          emp2=obj.GetEmployee(empID);
38.          Console.WriteLine(
39.            "Employee first name is: " +
40.            emp2.FirstName);
41.        }
42.     }
43. }

The only changed code is on lines 15 through 18. Notice that, on these lines, I specify the ICompany interface as the remote interface instead of the Company class in the call to the GetObject method on the System.Activator class. You cannot use the new operator because the new operator only works with classes. Organizing the code this way is functionally equivalent to the code I wrote earlier. The difference is that the implementation of Company marshal-by-reference class is hidden. You only need to share the ICompany interface and the marshal-by-value classes in the shared library. This is the recommended way to share types between .NET remoting clients and servers. It minimizes the amount of code that you need to share with the object's clients. Using interfaces is also a good way to minimize the coupling between the components in a component-based system because it allows you to change the implementation of a component completely without recompiling all of the code that uses the component. This is as true with .NET as it was with COM.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.179.186