Code Organization

Team-Fly    

 
.NET and COM Interoperability Handbook, The
By Alan Gordon
Table of Contents
Chapter Eleven.  .NET Remoting


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.


Team-Fly    
Top
 


. Net and COM Interoperability Handbook
The .NET and COM Interoperability Handbook (Integrated .Net)
ISBN: 013046130X
EAN: 2147483647
Year: 2002
Pages: 119
Authors: Alan Gordon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net