13

Remoting

 

Remoting is the practice of calling code from a dll, located on another machine using a web server.

 

Stipulated below are a few programs that unveil the concepts of remoting. After wading through the basic concept of remoting, we shall explain the same concept in the context of SOAP.

 

In remoting, a program or a client situated in some location in the world, executes a function or some code contained in a dll, which could be residing on a server, at some other geographical location in the world.

 

In order to achieve the above, two sub-directories, i.e. ss for server and cc for the client need to be created. As we proceed ahead, the programs become progressively complicated. Hence, we call upon you to create  the above mentioned directories, in exactly the same manner as we have stated. We have explained a few concepts of remoting in a nutshell, in the earlier chapter. However, there is no harm in re-iterating the salient features again.

 

Once the directories have been created, create the files s.cs and o.cs in the folder ss, and run the batch file a.bat. This will produce an exe file called s.exe, and a dll file named o.dll. Then in the folder cc, create two files named c.cs and o.cs, and again run the batch file named a.bat. This would create two more files, c.exe and o.dll.

 

Thereafter, open up two DOS console boxes by using the Command Prompt option; and within one of the consoles, execute the server executable named s.exe, in the ss subdirectory. The program would neither show any output, nor would it quit.

 

Next, move on to the cc folder and run the client program c.exe. In this window, the value of 100 is displayed. Simultaneously, if you switch to the server window, you would notice that three lines have been displayed.

 

Server

s.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels.Http;

public class zzz

{

public static void Main()

{

HttpChannel c = new HttpChannel(8080);

ChannelServices.RegisterChannel(c);

RemotingConfiguration.RegisterWellKnownServiceType (Type.GetType("yyy,o"), "abc", WellKnownObjectMode.SingleCall);

System.Console.ReadLine();

}

}

 

o.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

public class yyy : MarshalByRefObject

{

public yyy()

{

Console.WriteLine("yyy Constructor");

}

public int pqr(String a)

{

Console.WriteLine("DLL " + a);

return 100;

}

}

 

a.bat

del *.exe

del *.dll

csc /t:library o.cs

csc s.cs /r:o.dll

 

Client

c.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class zzz

{

public static void Main()

{

HttpChannel c = new HttpChannel();

ChannelServices.RegisterChannel(c);

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

if (o == null)

System.Console.WriteLine("Error");

else

{

int i = o.pqr("vijay");

Console.WriteLine(i);

}

}

}

 

o.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

public class yyy : MarshalByRefObject

{

public yyy()

{

Console.WriteLine("yyy Constructor1");

}

public int pqr(String a)

{

Console.WriteLine("DLL1 " + a);

return 1000;

}

}

 

a.bat

del *.exe

del *.dll

csc /t:library o.cs

csc c.cs /r:o.dll

 

Output in Server

yyy Constructor

yyy Constructor

DLL vijay

 

Output in Client

100

 

Curtly speaking, the file o.dll is present in the folder ss. The function pqr gets executed from this file. The return value of this function, i.e. 100, is displayed in the client window. There is a file named o.dll in the cc folder, but no code is executed from it.

 

Now, let us attempt at understanding the programs more exhaustively.

 

We initially grapple with the server program named s.cs. As always, the file begins with the namespaces. The concept of namespaces is employed to evade clashes between names that are freely created and used by people in general. Then, an object c of type HttpChannel is created. The HttpChannel class uses the HTTP protocol, i.e. the Hyper Text Transfer Protocol, to transfer messages between the client and the server.

 

In the networking world, the hierarchy is as follows:

     First comes IP, the Internet Protocol.

     Next is the TCP or Transmission Control Protocol.

     This is followed by HTTP or Hyper Text Transfer Protocol, which is the very foundation of the World Wide Web.

 

The two email protocols of SMTP and POP3, and the File Transfer Protocol FTP are at the same level as HTTP. When two computers talk to each other, every packet that is transferred to and fro between them, is stamped with a number. This facilitates easy identification by various higher-level protocols. In the TCP/IP world, this number is known as a port number.

 

Then, we exploit the services of another class named ChannelServices, which is responsible for sending and receiving data on the specified Channel. The static RegisterChannel function, which accepts an IChannel interface as a parameter, is assigned a value of 'c'. Thus, we can safely infer that the HttpChannel class is derived from the IChannel interface. In place of HttpChannel, we could have used a TcpChannel.

 

Next, we press into action, another static function named RegisterWellKnowServiceType, from the class RemotingConfiguration. This function unfurls the code that is to be executed, along with its whereabouts. The first parameter to this function is a data type called Type. To place a value in this parameter, we use the static function GetType, with a class name and a dll name. The values of 'yyy' and 'o' signify that the class yyy has to be obtained from the library o.dll. Thus, not only do we specify a class name yyy, but also the name of the dll that contains the class. The comma serves as a delimiter.

 

Therefore, our server that is listening on port 8080, will permit others to access code from the class yyy in the dll file named o. The next parameter identifies and locates the code that is to be executed.

The URI specified here is 'abc'. The last parameter that is specified, can assume any of the two values of an enum: WellKnownObjectMode, SingleCall or Singleton. The value of SingleCall specified in the program, ensures that every time a client calls some code in the server, the server shall use a new instance of the class yyy. The ReadLine function freezes execution of all the code. As a consequence, the server does not quit out.

 

Let us now shift our focus to the class yyy, which exposes the function pqr.

 

In the file o.cs, class yyy is derived from the class MarshalByRefObject. If we fail to derive from this class, a runtime exception gets generated. This is because of the fact that, the class MarshalByRefObject is the base class for all objects that are to be remoted. In the class, we have a constructor yyy, whose sole task is to print a string. We also have a function pqr, which accepts a string and returns the number 100.

 

The client c.cs in the cc folder starts with an HttpChannel object c. The constructor uses the default port number, unlike the case of the server, where we had to specify the number 8080. As is apparent from the server, a Channel object is registered. The object yyy that is located on the server machine and which is identified by the uri, is then activated on the client.

 

In our simulation, the client and server are on two different dos boxes; although in real time, they could be located miles apart. Therefore, the object has to be activated on a remote machine. To accomplish this, the Activator class is used, which finally returns a handle to that object.

 

To rephrase it in simple words, in order to create an object on a local machine, the 'new' keyword is used. On the other hand, to create an object remotely, so that it can be accessed on the machine as a local object, we use the static function GetObject from the Activator. This function accepts two parameters:

     The first is yyy, the type of the object that is to be created.

     The second is a URL in a string format, which points to the location of the server.

The URL starts with http, since the transport mechanism used is similar to the http protocol. After the colon and the two slashes, i.e. ://, the address of the server is specified. Since it is on our local machine, we specify the address as 'localhost'. The number 8080 following the colon symbol, is the port number where the server awaits all calls. The name of our server or URI is specified as 'abc'. Therefore, we conclude the above string with the URI of abc.

 

The server actually has a URI of abc on port 8080. Thus, it returns a valid object, from which the function pqr is called. This function pqr is executed off the server, and returns 100 in the variable i. The value of i is then displayed.

 

In the server window, the yyy constructor gets called twice, while the pqr function gets called once. The code in o.dll gets called from the server and not from the client. The constructor gets called twice on account of the call to the pqr function, and not because of the GetObject function.

 

If we comment out the call of the pqr function in the client, no output is witnessed in the server window. This elucidates the indispensability of o.dll in both the dos boxes. This is the smallest remoting example possible, but we are not sure if you have been able to grasp it fully or not. The documentation states that Remoting uses SOAP, although we still have no clue as to how it does so. The point to be noted here is that, the client and the server interact with each other. As an upshot of this interaction, some code gets executed.

 

Now, we write our own code, which divulges the communication between the client and the server. We make no alterations to the code in the client.

 

a.cs

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.IO;

class zzz  {

public static void Main()

{

TcpListener t = new TcpListener(8080);

t.Start();

Socket s = t.AcceptSocket();

byte [] b = new byte[1000];

int h1 = s.Receive(b);

String a = Encoding.ASCII.GetString(b);

System.Console.WriteLine(a);

byte [] c = new byte[1000];

int h2 = s.Receive(c);

String a1 = Encoding.ASCII.GetString(c);

System.Console.WriteLine(a1);

Console.ReadLine();

}

}

 

>csc a.cs

 

Output in the proxy

POST /abc HTTP/1.1

User-Agent: Mozilla/4.0+(compatible; MSIE 6.0; Windows 5.0.2195.0; MS .NET Remoting; MS .NET CLR 1.0.2914.16 )

SOAPAction: "http://schemas.microsoft.com/clr/nsassem/yyy/o#pqr"

Content-Type: text/xml; charset="utf-8"

Content-Length: 477

Expect: 100-continue

Connection: Keep-Alive

Host: localhost

 

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV=" http://schemas.xmlsoap.org/soap/envelope/ " SOAP-ENV:encodingStyle =" http://schemas.xmlsoap.org/soap/encoding/ " xmlns:i2=" http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a id="ref-3">vijay</a>

</i2:pqr>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

In addition to the existing folders, we now create one more folder named 'p', to accommodate the above program named a.cs. Then, we compile it to generate the file a.exe. Now, we would like you to run this program first, followed by the client.

 

After a few seconds, press Control-C in the client dos box and quit out of the waiting client. Now, switch over to the dos box where the a.exe program is running in the 'p' folder. You will notice the junk displayed above. Press enter and quit out of this program too.

 

The folder 'p' contains code for the proxy. The output seen in the dos box is a SOAP message. Before we launch forth into the SOAP world, a salient point to be noted is that, the server program was never executed.

 

We shall not dig any deeper and dissect the workings of the proxy program, as most of it has been expounded in the first chapter, while understanding the spy program. The client too has been explained earlier on. Hence, we shall not mull over it again.

 

It suffices to say that, the name of the function to be executed is pqr, and there also exists a tag with the same name. Now, to enable others to execute a function called pqr, the tag is prefaced with the unique namespace i2, created earlier in the code.

 

The pqr tag so formed, is now unique across the seven seas. It takes an attribute id, which has been assigned a value of ref-1. The id attribute is used to furnish the tag with a unique name. The function takes one parameter named 'a', with a value of 'vijay'. Therefore, there exists a child tag 'a' with an id attribute of ref-3. It appears as if they have missed out ref-2 ;-). The content given to this tag 'a' is 'vijay', because the function pqr is called with this value. Following this tag, are the three closing tags for pqr, Body and Envelope.

 

Thus, to call any function, a tag with the name of the function is created, and the parameter values are passed as content between tags accepting the parameter name. This assists in identifying the different parameter values in a function.

 

 

s.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Tcp;

using System.Runtime.Remoting.Channels.Http;

public class zzz

{

public static void Main()

{

HttpChannel c = new HttpChannel(8081);

ChannelServices.RegisterChannel(c);

RemotingConfiguration.RegisterWellKnownServiceType(Type.GetType("yyy,o"), "abc", WellKnownObjectMode.SingleCall);

System.Console.ReadLine();

}

}

 

a.cs

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.IO;

class zzz {

public static void Main()

{

TcpListener t = new TcpListener(8080);

t.Start();

Socket s = t.AcceptSocket();

byte [] b = new byte[1000];

int h1 = s.Receive(b);

String a = Encoding.ASCII.GetString(b);

System.Console.WriteLine(a);

byte [] c = new byte[1000];

int h2 = s.Receive(c);

String a1 = Encoding.ASCII.GetString(c);

System.Console.WriteLine(a1);

TcpClient t1 = new TcpClient();

t1.Connect("127.0.0.1", 8081);

NetworkStream s1 = t1.GetStream();

s1.Write(b,0,h1);

s1.Write(c, 0,h2 );

byte [] d = new byte[1000];

int h3 = s1.Read(d,0,1000);

String a2 = Encoding.ASCII.GetString(d);

System.Console.WriteLine(a2);

byte [] d1 = new byte[1000];

h3 = s1.Read(d1,0,1000);

a2 = Encoding.ASCII.GetString(d1);

System.Console.WriteLine(a2);

byte [] d2 = new byte[1000];

int h4 = s1.Read(d2,0,1000);

a2 = Encoding.ASCII.GetString(d2);

System.Console.WriteLine(a2);

s.Send(d1,h3,SocketFlags.None);

s.Send(d2,h4,SocketFlags.None);

}

}

 

Output

POST /abc HTTP/1.1

User-Agent: Mozilla/4.0+(compatible; MSIE 6.0; Windows 5.0.2195.0; MS .NET Remoting; MS .NET CLR 1.0.2914.16 )

SOAPAction: "http://schemas.microsoft.com/clr/nsassem/yyy/o#pqr"

Content-Type: text/xml; charset="utf-8"

Content-Length: 477

Expect: 100-continue

Connection: Keep-Alive

Host: localhost

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:i2="http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a id="ref-3">vijay</a>

</i2:pqr>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

HTTP/1.1 100 Continue

 

HTTP/1.1 200 OK

Content-Type: text/xml; charset="utf-8"

Server: MS .NET Remoting, MS .NET CLR 1.0.2914.16

Content-Length: 490

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:i2="http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqrResponse id="ref-1">

<return>100</return>

</i2:pqrResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

In the server program, the port number in the HttpChannel constructor has been changed to 8081. Thus, the server will now accept all packets that are destined for the port number 8081.

 

Now, to run the above program, we open up three dos boxes. The first one is for the proxy server called a.exe, in the folder p. The server program s.exe will be executed from the ss directory, in the second dos box. These two programs do not show any output at all. In the third dos box, we move on to the client folder cc and run the program c.exe, which initiates some process and generates the above output.

 

The proxy console displays additional data that was not visible earlier. The newly introduced output is the SOAP message sent by the server to the client.

 

As is essentially the case, the SOAP payload sent by the server starts with the Envelope root, containing all the namespace definitions. The Envelope tag is followed by the Body tag, and since this is the Response of the pqr function, the tag is pqrResponse. It takes an id of ref-1. There can be only one return value, which is placed in the return tag. The value enclosed in this tag is the return value of 100. The namespace, as usual, is i2.

 

In the proxy server, a considerable amount of code has been introduced. The proxy resembles the spy program that we had examined in the earlier chapter. In case you need to refresh your memory, you can flip through the pages and revise it once again. The program has been introduced to prove that, in the world of remoting, the client and server chat with each other using SOAP.

 

a.cs

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.IO;

class zzz

{

public static void Main()

{

TcpListener t = new TcpListener(8080);

t.Start();

Socket s = t.AcceptSocket();

byte [] b = new byte[1000];

int h1 = s.Receive(b);

String a = Encoding.ASCII.GetString(b);

System.Console.WriteLine(a);

byte [] c = new byte[1000];

int h2 = s.Receive(c);

String a1 = Encoding.ASCII.GetString(c);

System.Console.WriteLine(a1);

String s1 = "HTTP/1.1 200 OK\nContent-Type: text/xml; charset=\"utf-8\"\nServer: MS .NET Remoting, MS .NET CLR 1.0.2914.16\nContent-Length: 491\n\n";

Byte[] d1 = Encoding.ASCII.GetBytes(s1);

String s2;

s2 = "<SOAP-ENV:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:i2=\"http://schemas.microsoft.com/clr/nsassem/yyy/o\"><SOAP-ENV:Body><i2:pqrResponse id=\"ref-1\"><return>100</return></i2:pqrResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>";

Byte[] d2 = Encoding.ASCII.GetBytes(s2);

s.Send(d1);

s.Send(d2);

}

}

 

Output

POST /abc HTTP/1.1

User-Agent: Mozilla/4.0+(compatible; MSIE 6.0; Windows 5.0.2195.0; MS .NET Remoting; MS .NET CLR 1.0.2914.16 )

SOAPAction: "http://schemas.microsoft.com/clr/nsassem/yyy/o#pqr"

Content-Type: text/xml; charset="utf-8"

Content-Length: 477

Expect: 100-continue

Connection: Keep-Alive

Host: localhost

 

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:i2="http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a id="ref-3">vijay</a>

</i2:pqr>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

                                                                                                                                                                       

Client Output

100

 

Modify the proxy code in a.cs and then run the executable. There is no requirement of running the server. Therefore, we go ahead and run the client program 'c' from the folder cc.

 

 

The output shown in the proxy dos box is the message, sent by the client to the server. Surprisingly, in spite of not having a server running, the client console still exhibits a value of 100. This is due to the fact that the proxy code introduced here, deceives the client into believing that it is actually a remoting server, which in reality, it is not.

 

Let us unravel the code in the proxy program.

The TcpListener, as always, listens on port 8080, which is the same port that the client wants to connect to. Then, there is a wait for a connection at the blocking function AcceptSocket. The data dispatched by the client is then displayed on the console, though it is not used anywhere.

 

The program introduces two strings, s1 and s2, which are initialized to values shown in the output of the earlier program. These were the bytes that the server had sent across, when it received a packet from the client. After these two strings have been initialised, the packet is sent across to the client. As a result, the value of 100 is displayed on the screen, since it is enclosed within the return tag.

 

Therefore, there is no need for the client to be familiar with the identity of the sender of the packets. In any case, there is no way of determining this. The server could be a Java program, for all that the client cares.

 

Clients and servers talk to each other via SOAP. Therefore, they are not required to be cognizant of the intricacies of programming languages, Operating Systems, etc. SOAP messages are sent over HTTP, and software at the endpoint is of no prime concern. This is one of the several reasons why people are of the opinion that SOAP is revolutionizing the world of Distributed Computing.

 

a.cs

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.IO;

class zzz {

public static void Main()

{

TcpListener t = new TcpListener(8080);

t.Start();

Socket s = t.AcceptSocket();

byte [] b = new byte[1000];

int h1 = s.Receive(b);

String a = Encoding.ASCII.GetString(b);

string s5;

s5 = "<SOAP-ENV:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:i2=\"http://schemas.microsoft.com/clr/nsassem/yyy/o\">\n<SOAP-ENV:Body>\n<i2:pqr id=\"ref-1\">\n<a id=\"ref-3\">vijay</a>\n</i2:pqr>\n</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\n\n\n\n\n\n\n\n";

Byte[] l1 = Encoding.ASCII.GetBytes(s5);

String ss1 = Encoding.ASCII.GetString(l1);

byte [] c = new byte[1000];

int h2 = s.Receive(c);

String a1 = Encoding.ASCII.GetString(c);

TcpClient t1 = new TcpClient();

t1.Connect("127.0.0.1", 8081);

NetworkStream s1 = t1.GetStream();

s1.Write(b, 0,h1 );

s1.Write(l1, 0,l1.Length );

byte [] d = new byte[1000];

int h3 = s1.Read(d,0,1000);

String a2 = Encoding.ASCII.GetString(d);

byte [] d1 = new byte[1000];

h3 = s1.Read(d1,0,1000);

a2 = Encoding.ASCII.GetString(d1);

byte [] d2 = new byte[1000];

int h4 = s1.Read(d2,0,1000);

a2 = Encoding.ASCII.GetString(d2);

s.Send(d1,h3,SocketFlags.None);

s.Send(d2,h4,SocketFlags.None);

}

}

The above-mentioned program is analogous to the first proxy server in the chapter. The proxy reads the two packets sent by the client. The only difference being, that the second packet from the client is not sent across in its original form. Instead, the proxy creates the packet and sends it to the server. Thus, the client and the server are merely interested in the SOAP payload, and not in the identity of its creator.

 

The presence of too many folders, leads to clutter and confusion. Thus, for the next program we have a single folder named 'rr', where we position the client c.cs, the server s.cs and the dll o.cs. We place them all in a single folder for the sake of convenience. In real life, they could be spread over different machines. The server program remains the same, and on careful scrutiny, you would notice that there is no mention of the pqr function in the server program.

 

a.cs

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.IO;

class zzz

{

public static void Main()

{

TcpListener t = new TcpListener(8080);

t.Start();

Socket s = t.AcceptSocket();

byte [] b = new byte[1000];

int h1 = s.Receive(b);

String a = Encoding.ASCII.GetString(b);

System.Console.WriteLine(a);

byte [] c = new byte[1000];

int h2 = s.Receive(c);

String a1 = Encoding.ASCII.GetString(c);

System.Console.WriteLine(a1);

TcpClient t1 = new TcpClient();

t1.Connect("127.0.0.1", 8081);

NetworkStream s1 = t1.GetStream();

s1.Write(b,0,h1);

s1.Write(c, 0,h2 );

byte [] d = new byte[1000];

int h3 = s1.Read(d,0,1000);

String a2 = Encoding.ASCII.GetString(d);

System.Console.WriteLine(a2);

byte [] d1 = new byte[1000];

h3 = s1.Read(d1,0,1000);

a2 = Encoding.ASCII.GetString(d1);

System.Console.WriteLine(a2);

byte [] d2 = new byte[1000];

int h4 = s1.Read(d2,0,1000);

a2 = Encoding.ASCII.GetString(d2);

System.Console.WriteLine(a2);

s.Send(d1,h3,SocketFlags.None);

s.Send(d2,h4,SocketFlags.None);

}

}

                                                                                                                                                  

s.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class zzz

{

public static void Main()

{

HttpChannel c = new HttpChannel(8081);

ChannelServices.RegisterChannel(c);

RemotingConfiguration.RegisterWellKnownServiceType(Type.GetType("yyy,o"), "abc", WellKnownObjectMode.SingleCall);

Console.ReadLine();

}

}

 

c.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class zzz

{

public static void Main()

{

HttpChannel c = new HttpChannel();

ChannelServices.RegisterChannel(c);

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

o.pqr(100);

}

}

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(int  a)

{

}

}

 

a.bat

del *.exe

del *.dll

csc /t:library o.cs

csc s.cs /r:o.dll

csc c.cs /r:o.dll

csc a.cs

 

Output

POST /abc HTTP/1.1

User-Agent: Mozilla/4.0+(compatible; MSIE 6.0; Windows 5.0.2195.0; MS .NET Remoting; MS .NET CLR 1.0.2914.16 )

SOAPAction: "http://schemas.microsoft.com/clr/nsassem/yyy/o#pqr"

Content-Type: text/xml; charset="utf-8"

Content-Length: 464

Expect: 100-continue

Connection: Keep-Alive

Host: localhost

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:i2="http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a>100</a>

</i2:pqr>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

HTTP/1.1 200 OK

Content-Type: text/xml; charset="utf-8"

Server: MS .NET Remoting, MS .NET CLR 1.0.2914.16

Content-Length: 468

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:i2="http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqrResponse id="ref-1">

</i2:pqrResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

This program highlights one of the most important features of SOAP, i.e. functions with parameters. These parameters are packaged as an XML document and then sent across. The same process is followed for return values.

 

Now, we shall demystify the mechanism by which SOAP packages the data types, which are passed with the parameters.

 

In our client program, the only change for next couple of programs is, call of the function pqr with different parameter types. In this example, the parameter has the datatype of int. As of now, there is no return value.

 

We intend to showcase the varied types of calls that can be made. We will display only the modified code in the latter part of the c.cs file. The dll will have different iterations of the function being called. Also, no output is displayed either in the client, or in the server, or in the dll. Our objective is to figure out how the parameters are packaged as an XML document.

 

The a.bat file is a straightforward and an uncomplicated one. It creates the executables for the client and the server. In the first dos box, we run the proxy a.exe. Then, in the second dos box, we run the server 's'. Finally, in the last dos box, the client program 'c' is run. To quit out of the server, simply press the enter key.

 

In the proxy console, we shall display the output from the point where the body tag begins, since everything upto this point, remains the same. The number 100 is packaged across, without the data type being specified anywhere.

 

As mentioned earlier, only the parameter name is sent across in the form of tag names. The data type of the parameter is not visible in the XML document. The same holds true for the response too. Since there is no return value, the return tag is also non-existent. Hence, the return packet also remains unchanged. Thus, for the time being, we shall not display the return SOAP payload too.

 

c.cs

o.pqr(100,"vijay",false);

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(int  a , string b, bool c)

{

}

}

 

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a>100</a>

<b id="ref-3">vijay</b>

<c>false</c>

</i2:pqr>

</SOAP-ENV:Body>

 

In the client program, function pqr is called with three parameters - an int, a string and a bool. The int and bool are basic data types, and hence, are bereft of an id. However, the string being a complexType, has an id of ref-3. The data types follow the rules of XML Schemas.

 

The o.dll is modified to incorporate the parameters, as the parameter names are picked up from this library. Thus, simple types like int, do not possess any id attributes, whereas, complex types do.

 

Out Parameters

 

c.cs

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class zzz

{

public static void Main()

{

HttpChannel c = new HttpChannel();

ChannelServices.RegisterChannel(c);

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

int i,j;

i = 1000;

o.pqr(out i, out j, 200);

Console.WriteLine(i + " " + j);

}

}

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(out int a, out int b, int p)

{

a = 10;

b = 20;

}

}

 

Output

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<p>200</p>

</i2:pqr>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

<SOAP-ENV:Body>

<i2:pqrResponse id="ref-1">

<a>10</a>

<b>20</b>

</i2:pqrResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Client Output

10 20

 

The above example deals with the 'out' parameter. For those of you who are not well acquainted with the 'out' parameter, we restate that it does not have to be initialized while calling the function. It is the responsibility of the function to initializes the 'out' parameter, or else, an error is generated. The function that is called, is also not entitled to access the value of the 'out' parameter, since its value does not have to be initialized before the function is called.

 

In the file c.cs, the function pqr has two 'out' parameters, i and j. The value of the variable i is set to 1000, while j is not initialized. The last parameter is a simple by-value parameter. In o.dll, the variables of i and j are initialized to the values of 10 and 20, respectively. If we do not initialize them, an error will be generated.

 

The output expressly reveals that the initial SOAP Message is under the assumption that there is a single parameter 'p', with a value of 200. There is no trace of the 'out' parameters, despite the fact that one of them has been initialized. As a matter of fact, there is no need for them to contain a value. Hence, sending a value over is merely an exercise in futility. In the return SOAP payload, the two 'out' parameters named 'a' and 'b' are visible as tags, with their values of 10 and 20.

 

The 'out' parameters are sent back to the client, unlike the 'in' parameters, which are sent from the server.

 

c.cs

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

int i;

i = 1000;

o.pqr(ref i);

Console.WriteLine(i);

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(ref int a)

{

a = 10;

}

}

 

Output

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a>1000</a>

</i2:pqr>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

<SOAP-ENV:Body>

<i2:pqrResponse id="ref-1">

<a>10</a>

</i2:pqrResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

Client Output

10

 

The 'ref' parameter must be initialized before it is assigned to a function. The called function may or may not change its value, but it can access it and use its value.

 

The function pqr takes one ref parameter, which is initialized to 1000. In the server, the value is changed to 10.

 

To recapitulate, in the initial SOAP payload, the value of 1000 is sent across; and in the return packet, the altered value of 10 is seen, with the parameter 'a'.

 

Thus, the 'in' parameters, which are the default parameters, are present only in the packet that is sent from client to server. The 'out' parameters are sent from the server to the client. The 'ref' parameters are the only ones that are transmitted in both directions, from the client to the server, and also from the server to the client.

 

Arrays

 

c.cs

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

int [] z;

z = new int[3]{10, 34, 56};

o.pqr(z);

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(int []  a )

{

}

}

 

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a href="#ref-3"/>

</i2:pqr>

<SOAP-ENC:Array id="ref-3" SOAP-ENC:arrayType="xsd:int[3]">

<item>10</item>

<item>34</item>

<item>56</item>

</SOAP-ENC:Array>

</SOAP-ENV:Body>

 

The function pqr now takes an array of ints. Therefore, in the client program, we create an array 'z' of three ints, and then assign it as a parameter to the function. In the dll, the function pqr accepts this array in a parameter called 'a'.

 

The output reveals that in the Body element, tag 'a' contains an attribute href, with a value of #ref-3. This is the only information furnished along with the pqr function tag. Furthermore, for the first time, the Array tag from the SOAP-ENC namespace has been used.

 

The first attribute of the array tag is an id ref-3, which is used for the href attribute. Thus, the 'a' tag is now an array with an id of ref-3. The second attribute arrayType, also from the SOAP-ENC namespace, states that the array has a size of three, and its data type is an int from the namespace xsd. Following this is the item tag, which enumerates the three value of the array viz. 10, 34 and 56.

 

c.cs

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

int [] z;

z = new int[3]{10, 34, 56};

string  [] y;

y = new string[3]{"Hi", "bye", "no"};

o.pqr(z,y);

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(int []  a , string [] b)

{

}

}

 

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a href="#ref-3"/>

<b href="#ref-4"/>

</i2:pqr>

<SOAP-ENC:Array id="ref-3" SOAP-ENC:arrayType="xsd:int[3]">

<item>10</item>

<item>34</item>

<item>56</item>

</SOAP-ENC:Array>

<SOAP-ENC:Array id="ref-4" SOAP-ENC:arrayType="xsd:string[3]">

<item id="ref-5">Hi</item>

<item id="ref-6">bye</item>

<item id="ref-7">no</item>

</SOAP-ENC:Array>

</SOAP-ENV:Body>

 

After having worked with an array of ints, we anatomize the two arrays, one of which is a string, and the other is an int. Thus, in the client program, we create an array named y, which has three strings.

 

Then, we pass these two arrays 'z' and 'y' to the pqr function. In the SOAP payload, there is a pqr tag, which has an attribute id with a value of ref-1. It contains two child elements a and b, which correspond to the names of the two parameters. Both of them have an href attribute each, which states the data type of these parameters that have been created elsewhere. The first Array element has an id of ref-3, and it specifies that the arrayType is an array of three ints.

 

The second Array element has an id of ref-4. It is an array of three strings. The difference here is that the item tag now contains a string, an XML Schema complex type, and thus, has ids of ref-5, ref-6 and ref-7. This is the only known difference between an array of simple types and that of a complex type.

 

c.cs

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

int[,] a = new int[3, 2] { {10, 20}, {30, 40}, {50, 60} };

o.pqr(a);

 

o.cs

public class yyy : System.MarshalByRefObject {

public void pqr(int [,] a)

{

}

}

Output

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a href="#ref-3"/>

</i2:pqr>

<SOAP-ENC:Array id="ref-3" SOAP-ENC:arrayType="xsd:int[3,2]">

<item>10</item>

<item>20</item>

<item>30</item>

<item>40</item>

<item>50</item>

<item>60</item>

</SOAP-ENC:Array>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

                                                                                                                                                                                                                                                                                                                                                        

Illustrated above is an example of a multi-dimensional array. A multi-dimensional array of size 3 by 2 is created, and simultaneously, it is initialized to some numbers. While passing the array to the function pqr, the size of the array is not mentioned. Only the fact that it is a multidimensional array, is specified.

 

The SOAP payload displays a tag 'a', which refers to the array having the id of ref-3. The Array tag has an array type of int, and its dimensions are 3 by 2. The item tag stores these values in the sequence, as was used while initializing the array.

 

Thus, there is not much variation between the handling of single and multi-dimensional arrays.

 

Params parameters

 

c.cs

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

o.pqr("hi",10,20,30);

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(string a, params int [] i)

{

System.Console.WriteLine(i[0] +  " " + i[1] + " " + i[2]);

}

}

 

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a id="ref-3">hi</a>

<i href="#ref-4"/>

</i2:pqr>

<SOAP-ENC:Array id="ref-4" SOAP-ENC:arrayType="xsd:int[3]">

<item>10</item>

<item>20</item>

<item>30</item>

</SOAP-ENC:Array>

</SOAP-ENV:Body>

 

In the above example, the function pqr takes one string and three ints. In the dll, the ints are consumed by a params parameter.

 

The SOAP payload reveals the fact that the array of three ints is sent across as a single array, and not as individual int parameters. This is because, the prototype or code of the function specifies a params parameter.

 

Thus, the three ints are first fused together into a single array, and then, the resultant array is sent across the wire. For some reason, the name ref-2 is never used. Maybe some people down there are superstitious. The string parameter 'a' has a reference to ref-3, which is not used at all. The arrayType attribute is made up of a simple array of three ints.

 

Jagged arrays

 

c.cs

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

int[][] a = new int[2][] { new int[] {1,2,3}, new int[] {4,5} };

o.pqr(a);

 

 

o.cs

public class yyy : System.MarshalByRefObject

{

public void pqr(int[][]a)

{

}

}

 

Output

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:a1="http://schemas.microsoft.com/clr/ns/System" xmlns:i2="http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a href="#ref-3"/>

</i2:pqr>

<SOAP-ENC:Array id="ref-3" SOAP-ENC:arrayType="a1:Int32[][2]">

<item href="#ref-4"/>

<item href="#ref-5"/>

</SOAP-ENC:Array>

<SOAP-ENC:Array id="ref-4" SOAP-ENC:arrayType="xsd:int[3]">

<item>1</item>

<item>2</item>

<item>3</item>

</SOAP-ENC:Array>

<SOAP-ENC:Array id="ref-5" SOAP-ENC:arrayType="xsd:int[2]">

<item>4</item>

<item>5</item>

</SOAP-ENC:Array>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

The client file now has a jagged array containing two arrays. Once the jagged array has been created, the other two arrays are created, with each having three and two members, respectively. Thus, the jagged array has two arrays, which in turn, have arrays of different lengths.

Finally, it is the data type that matters the most. In this case, it is an int. When a jagged array is specified, the length parameter is never taken into consideration.

 

With the introduction of the jagged array, the variation that we encounter is that, in the Envelope tag, an additional namespace prefix has been created. The namespace points to a regular namespace at Microsoft. In the body, the array is referred to as ref-3. While creating this array, the namespace of 'a1', and not 'xsd', is used. The Int32 alias is used in lieu of int for the data type of the arrayType attribute. The id of ref-3 defines the first or outer array of the two members.

 

Since there are two members, the SOAP payload shows two item tags, which in turn, define two items with a href value of ref-4 and ref-5, respectively. From here onwards, life proceeds normally. There are two arrays of ints, which have three and two members, respectively. This makes sense, since a jagged array is merely a collection of individual arrays of different sizes and shapes.

 

Thus, the first array definition specifies the individual arrays, and the other array definitions specify the arrays that constitute the jagged array.

 

Passing Objects

 

Change one line in the proxy program as given below:

byte [] c = new byte[10000];

 

This change has to be initiated because the SOAP payload is extremely bulky. We could have specified a bigger number at the initial stage itself, but then, the use of large numbers, would have resulted in the display of more blank lines.

 

c.cs

yyy o = (yyy) Activator.GetObject(typeof(yyy), "http://localhost:8080/abc");

ppp b;

b = new ppp();

o.pqr(b);

o.cs

public class ppp : System. MarshalByRefObject

{

}

public class yyy : System.MarshalByRefObject

{

public void pqr(ppp a)

{

}

}

 

Output

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:a3=" http://schemas.microsoft.com/clr/ns/System.Runtime.Remoting.Channels" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Runtime.Remoting" xmlns:i2="http://schemas.microsoft.com/clr/nsassem/yyy/o">

<SOAP-ENV:Body>

<i2:pqr id="ref-1">

<a href="#ref-3"/>

</i2:pqr>

<a1:ObjRef id="ref-3">

<uri id="ref-4">/c9c24653_7764_4ee5_a135_bbccc476795f/1.rem</uri>

<objrefFlags>0</objrefFlags>

<typeInfo href="#ref-5"/>

<envoyInfo xsi:null="1"/>

<channelInfo href="#ref-6"/>

</a1:ObjRef>

<a1:TypeInfo id="ref-5">

<serverType id="ref-7">ppp, o, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</serverType>

<serverHierarchy xsi:null="1"/>

<interfacesImplemented xsi:null="1"/>

</a1:TypeInfo>

<a1:ChannelInfo id="ref-6">

<channelData href="#ref-8"/>

</a1:ChannelInfo>

<SOAP-ENC:Array id="ref-8" SOAP-ENC:arrayType="xsd:ur-type[1]">

<item href="#ref-9"/>

</SOAP-ENC:Array>

<a3:CrossAppDomainData id="ref-9">

<_ContextID>1294864</_ContextID>

<_DomainID>1</_DomainID>

<_processGuid id="ref-10">5ae7cd65_b8a1_41bf_afdd_208f1d948096</_processGuid>

</a3:CrossAppDomainData>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

 

In the client, the object 'b' is created as an instance of class ppp. This object is then passed as a parameter to the function pqr. Effectively, we are passing a real-life object or a reference type to a function. The file o.cs defines the class ppp. It must be derived from the class MarshalByRefObject, or else, a runtime exception will be thrown. All remoting objects have to be derived from the above-mentioned class. There is absolutely no code in the class ppp. Despite this, the size of the SOAP payload increases, as an actual object is now being sent over.

 

As usual, the Envelope element shows the namespaces, but now 'a3' and 'a1' are also present. Unlike the namespace i2, both these namespaces are fixed, and are not related to the code. The Body element, like before, begins with the pqr element from the i2 namespace, and consists of a single parameter 'a', having a href to ref-3.

 

This is not an array reference, but an ObjRef datatype, belonging to the namespace 'a1'. The System.Runtime.Remoting namespace, holding the class called ObjRef, represents the class ppp across the wire. Thus, an instance of an ObjRef class has been used, to send across an object of type ppp, from the client to the server.

 

In remoting terminology, it is described as a transfer across an AppDomain boundary. Thus, an ObjRef object, as seen in the SOAP payload, represents the serialized version of the ppp object. This act of sending something over the wire is termed as 'marshaling'.

 

We are not required to create an ObjRef object, since it is created by the remoting infrastructure, whenever we have to send across a reference object. This is not applicable to value objects, such as- int. This ObjRef object contains all the information about the object being remoted. This information describes entities like, the type and class of the object, its location and the pathway to reach the object stored on a remote server.

 

The class ppp that is derived from MarshalByRefObject, is converted into an ObjRef object, using a process called 'marshalling'. At the remote server, the ObjRef is converted into a proxy, or to be more accurate, a 'transparent proxy', which represents the remoted object. This process is known as 'un-marshaling'. The proxy is termed as a transparent proxy, since the client is given to believe that the proxy represents the actual object.

 

The original object resides only on the remote machine. Therefore, from the client's point of view, the proxy represents the actual object in its own memory space. It is like the relationship between a magician and a fool. It is the task of the proxy to forward all calls made on it, to the original object on the server, using the code provided by the remoting world.

 

The child element or a property of the ObjRef class called uri has an id attribute, which is of no significance right now. Its value is of type string, and it represents every unique instance of the object. We can thus identify every unique instance of the object by using this field. It is assigned an id of ref-4, and it contains a very large number, which is machine-generated.

 

In the computer world, in order to represent an entity uniquely across time and space, a 128-bit or a 16-byte number is used.

 

<uri id="ref- 4">/e6e488e0_0ef3_4204_9a80_cb9ced35dfe8/1.rem< /uri>

<uri id="ref- 4">/ed1dc61f_911a_4a74_922a_8aed0cf44fd7/1.rem< /uri>

 

Run the same program again, and observe that a different value is generated for the uri field. The value specified above becomes a handle, and uniquely represents the ppp object 'a'. We cannot explain the tag objrefFlags, whose value is 0, since it has not been documented anywhere. It appears as though the documentation is also at the beta stage.

 

Next, we have a tag typeInfo, which has a href to an element with an id of ref-5. This tag is a TypeInfo, from the 'a1' namespace, and it starts with the capital letter T. This element TypeInfo has three children or properties, as per the SOAP payload. The documentation specifies the datatype for this property to be an interface IremotingTypeInfo, which has only one property TypeName, of type string.

 

Though we are in no position to explain the above three child members, we shall still endeavour to do so. The TypeInfo object contains considerable information about the type of the remote object that the ObjRef represents. In our case, it is of type yyy. Also, the type hierarchy or the classes that it derives from, as well as the interfaces it implements, need to be ascertained. The proxy requires this data, to communicate with the client. The interfacesImplementated does not have any content, since the class ppp does not implement any interfaces.

 

The xsi:null attribute determines whether a null value can be used as the value of an element or not. If yes, then the element can have a value of null.

 

The serverType element is made up of a list of values, which are delimited by commas, as follows:

     It starts with the class named ppp.

     This is followed by the name of the dll file 'o'.

     Next is the version number.

     This is followed by a Culture.

     After this, comes a Public key value.

     The last two values can either be null or they may have no values at all.

 

The EnvoyInfo element too does not have any content. This class or element of type IEnvoyInfo contains 'message sinks'. The element is required when runtime support is to be provided for transactions. The last child of ObjRef is a channelInfo element. This refers to a ChannelInfo with a capital letter C, having an id of ref-6. Its data type is the interface IChannelInfo.

 

This class handles different methods to communicate with the other side, using channels. It has one member channelData, which has a href attribute set to an element, with an id of href-8. This is an Array of type ur-type, and it has only one member.

 

An ur-type is the type defined in the XML Schemas world. It is this class that deals with transport specific issues. The channel data is copied from the channel into the SOAP payload. Subsequently, at the time of un-marshalling at the server end, this data is required to create a transport sink and manage further transmission of messages between the proxy and the server.

 

This array has only one child element item, which leads to the last id of href-9. This member is of type CrossAppDomainData, and it stores the data for each channel. The Context creates an environment for objects. The ContextID and DomainID do not change at all.

 

The last member processGuid embodies a different value, each time the program is executed.

 

<_processGuid id="ref- 10">eb0d4161_43c4_4548_b0eb_4eda7c 4022d2</_processGuid>

 

GUID, which is an acronym for a Globally Unique Identifier, is a 128-bit number, which is absolutely unique across time and space. The words GUID and UUID have originated from the world of ActiveX and OLE. This brings us to the end of our explanation of the SOAP payload.