9

Attributes

 

This chapter rivets around those attributes, which can be placed upon entities, such as- functions, classes, properties etc. in both, the asmx file, as well as, the proxy program.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Xml.Serialization;

public class zzz

{

[WebMethod]

public void abc(yyy a)

{

}

}

public class yyy

{

public int i;

public xxx k;

public int j;

}

public class xxx {

public int x1,x2;

}

a.cs

class aaa

{

public static void Main()

{

zzz a= new zzz();

yyy b = new yyy();

xxx c = new xxx();

b.i = 10;b.j = 20;

b.k = c;

c.x1 = 100; c.x2 = 200;

a.abc(b);

}

}

 

z.bat

del *.exe

del *.dll

del zzz.cs

wsdl aa.wsdl

csc /t:library zzz.cs

csc a.cs /r:zzz.dll

a

 

SOAP request

<abc xmlns="http://tempuri.org/">

<a>

<i>10</i>

<k>

  <x1>100</x1>

  <x2>200</x2>

  </k>

  <j>20</j>

  </a>

</abc>

 

In the asmx file, the function abc in class zzz accepts a parameter 'a', of type yyy. The class yyy has two int variables, i and j, and a third variable 'k', of type xxx. The class xxx contains two variables, x1 and x2.

 

 

In the browser, enter the url as http://localhost/a.asmx?WSDL and then, save the output in a file named aa.wsdl. Since, our very core of concern is the data encompassed in the SOAP packet that flows to and fro, we alter the port number of localhost to 8080, and banish the inane or worthless characters. Thereafter, the client proxy is generated, courtesy - the wsdl program. As the WSDL file and proxy introduce nothing that is really innovative, we give them the slip for a while.

 

The client program named a.cs, creates three objects, viz. xxx, yyy and zzz. The creation of a yyy object does not result in the creation of an xxx object automatically.  In fact, it has to be created expressly.

 

Thereafter, using object 'b' of type yyy, the 'k' member of type xxx is initialized to 'c', which is an xxx object. The other members of the yyy object are also initialized. The object 'b' is then passed as a parameter to the function abc.

 

As is customary, the SOAP request originates with the parameter 'a', which encloses its three members viz. i, j and k. Since the variable 'k' is also an object, it becomes the parent tag of the two members x1 and x2, which it embodies. Therefore, objects that are enclosed within other objects, carry their children together with them.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Xml.Serialization;

public class zzz

{

[WebMethod]

public void abc(yyy a)

{

}

}

public class yyy

{

public int i;

public xxx [] k;

public int j;

}

public class xxx

{

public int x1,x2;

}

 

a.cs

class aaa

{

public static void Main()

{

zzz a= new zzz();

yyy b = new yyy();

b.i = 10;b.j = 20;

xxx [] c = new xxx[2];

c[0] = new xxx();

c[0].x1= 20;c[0].x2= 21;

c[1] = new xxx();

c[1].x1= 200;c[1].x2= 201;

b.k = c;

a.abc(b);

}

}

 

SOAP request

<abc xmlns="http://tempuri.org/">

- <a>

  <i>10</i>

- <k>

- <xxx>

  <x1>20</x1>

  <x2>21</x2>

  </xxx>

- <xxx>

  <x1>200</x1>

  <x2>201</x2>

  </xxx>

  </k>

  <j>20</j>

  </a>

</abc>

 

 

In the asmx file, the variable 'k' is an array of xxx objects. Earlier, it had been declared as a simple variable. With the exception of this modification, everything else remains unaltered. The WSDL file and the client proxy are both generated as before.

 

Firstly, in the client program, an array called 'c', of xxx objects, is created. It has a size of 2. Both the arrays are initialized, by being referred to as c[0] and c[1]. The data displayed in the SOAP request is comprised of the three variables i, j and k. The variable 'k', being an array of two objects, contains two child elements called xxx. It is these child elements, which accommodate the array contents.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Xml.Serialization;

public class zzz

{

[WebMethod]

public void abc(yyy a)

{

}

}

public class yyy

{

public int i;

[XmlAttribute()]

public int j;

}

 

a.cs

class aaa

{

public static void Main()

{

zzz a= new zzz();

yyy b = new yyy();

b.i = 10;b.j = 20;

a.abc(b);

}

}

 

aa.wsdl

<s:complexType name="yyy">

  <s:sequence>

  <s:element minOccurs="1" maxOccurs="1" name="i" type="s:int" />

  </s:sequence>

<s:attribute name="j" type="s:int" />

</s:complexType> 

 

zzz.cs

public class yyy

{

public int i;

[System.Xml.Serialization.XmlAttributeAttribute()]

public int j;

[System.Xml.Serialization.XmlIgnoreAttribute()]

public bool jSpecified;

}

 

SOAP request

<a>

<i>10</i>

</a>

 

In the world of XML Serialization, we retain the prerogative to elect and settle upon the methodology, by means of which, the XML data shall be sent across the wire. By placing an attribute named XmlAttribute on the variable j in the wsdl file, it becomes evident that the complexType yyy has only one element called i. The variable j assumes the form of an attribute, instead of an element.

 

Thus, the WSDL honours the attribute. The a.cs file is not really plagued about whether 'j' is an attribute or an element. The client program remains absolutely unchanged. The proxy that is generated, has the attribute XmlAttributeAttribute placed on it, along with another member called jSpecified, with an attribute of XmlIgnoreAttribute on it.

 

Despite of our having assigned a value to variable 'j', it never gets reflected in the SOAP request. We were of the notion, that the value contained in 'j', would be sent out as an attribute. However, at this stage, it has completely been snubbed by the System.

Now, we just add another line to the a.cs file.

 

a.cs

b.i = 10;b.j = 20;

b.jSpecified = true;

a.abc(b);

 

SOAP request

<a j="20">

  <i>10</i>

  </a>

 

On initializing the jSpecified member to 'true', the SOAP request that is sent across, displays 'j' as an attribute to the parameter name 'a', with a value of 20. The default value assigned to the jSpecified variable is 'false'. Hence, it is for this reason that 'j' was not sent over the wire earlier on; in other words, it was not serialized.

 

If you replace the XmlAttribute with the attribute of SoapAttribute, the attribute would throw the following error: 

 

Output

a.cs(8,1): error CS0117: 'yyy' does not contain a definition for 'jSpecified'

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Xml.Serialization;

public class zzz  {

[WebMethod]

public void abc(yyy a) { }

}

public class yyy

{

[SoapAttribute()]

public int i;

[XmlAttribute(AttributeName="ddd")]

public int j;

}

 

aa.wsdl

<s:attribute name="ddd" type="s:int" />

 

zzz.cs

public class yyy

{

public int i;

[System.Xml.Serialization.XmlAttributeAttribute()]

public int ddd;

[System.Xml.Serialization.XmlIgnoreAttribute()]

public bool dddSpecified;

}

 

a.cs

class aaa

{

public static void Main()

{

zzz a= new zzz();

yyy b = new yyy();

b.i = 10;

b.ddd = 20;

b.dddSpecified = true;

a.abc(b);

}

}

 

SOAP request

<a ddd="20">

<i>10</i>

</a>

 

The AttributeName property is employed here, since our intention is to change the name of the variable, from 'j' to 'ddd'. Therefore, on generating the WDSL file, the name assigned to the attribute is 'ddd', and not 'j'.

 

In the proxy that is generated, the SoapAttribute is not affected. However, the name assigned to the bool variable is 'dddSpecified', thereby, reaffirming the change of the variable name to 'ddd'.

 

 

Both, the client program and the SOAP payload, refer to the variable as 'ddd', and not as 'j'. Thus, we can exercise absolute authority over the variables' names written in the SOAP payload.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz  {

[WebMethod(Description="vijay mukhi")]

public void abc()

{

}

}

 

aa.wsdl

 <portType name="zzzSoap">

<operation name="abc">

  <documentation>vijay mukhi</documentation>

  <input message="s0:abcSoapIn" />

  <output message="s0:abcSoapOut" />

  </operation>

  </portType>

 

a.cs

class aaa

{

public static void Main()

{

zzz a= new zzz();

a.abc();

}

}

 

The WebMethod attribute that remotes a function, contains a property called Description, which facilitates certain amount of documentation in the function abc. The wsdl file generated from the asmx file, has the portType element, which contains the operation element of abc. This is followed by the element documentation, which carries the name of 'vijay mukhi'.

 

 

In essence, this is what the Description property is all about. However, there is no mention of Description in the proxy that is generated, since the wsdl utility disregards the element completely.

 

Application and Session Objects

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz : WebService

{

[WebMethod()]

public int abc()

{

if (Application["zzz"] == null)

Application["zzz"] = 1;

else

Application["zzz"] = ((int) Application["zzz"]) + 1;

return  (int) Application["zzz"];

}

}

 

In the above asmx file, the class zzz is derived from the WebService class. This class has a property called Application, which is of type HttpApplicationState. The variables are created using the indexer. These are not variables in the real sense of the term, but they boast of all functionalities of a variable.

 

Thus, Application["zzz"] creates a variable named 'zzz'. Since it is not initialized, it has a value of null. When the abc function is invoked for the first time, the value of zzz gets set to 1. This may be ascertained by specifying the address http://localhost/a.asmx/abc? in the browser window.

 

The question mark at the end of the URL is optional, and is used when parameters are required to be supplied to the function abc. Now, click on the refresh button in the browser. This invokes the same function again.Since the Application object has the value of 1, it saves this last value of the zzz state variable, increments it by 1, and then, restores the new value. Therefore, the number 2 is displayed in the browser.

Leave the browser window as it is and open a new copy of IE. Then, enter the same Url. Now, the value that would be displayed is 3.

 

The HTTP protocol is referred to as 'stateless'. This is so because, as soon as the connection between the server and the client cleaves, all the activities and information related to the client and the server get obliterated. As a consequence, when we request the server for a new page, it entails re-establishment of connection between the two ends.

 

Thus, the process starts anew each time, proving to be irksome. The Application object is primarily utilized to maintain 'state', thereby, enabling the web server to keep track of the events that have transpired at its end.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz : WebService

{

[WebMethod(CacheDuration=6000,EnableSession=true)]

public int abc()

{

if (Session["zzz"] == null)

{

Session["zzz"] = 1;

}

else

{

Session["zzz"] = ((int) Session["zzz"]) + 1;

}

return  (int) Session["zzz"];

}

}

 

In the case of the Application property, the state is maintained as per the requirement of the machine, and not as per the browser. Consequently, the session object, with the variables by its side, is used to start the browser afresh each time. When we initiate a new copy of the browser, the count also starts with 1.

 

The state object zzz is restored with the copy of the browser. So, when a new browser instance is loaded, the variable zzz begins with the value of 1. The lacuna in this approach is that, the web server is bound to run into rough weathers and slow down considerably. The speed of the web server is trammeled because, there would be innumerable copies of the browser interacting with the server, and the server would have no choice but to maintain an equal number of copies of the variable zzz.

 

Thus, by default, the Session property is disabled. To enable it, we utilize the property of the WebMethod attribute, and activate EnableSession. The Session property uses Cookies to maintain state, or to uniquely identify an instance of a browser. The CacheDuration property determines the duration in seconds, for which the page should linger in the cache, before the system reads it again from its hard disk.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz : WebService

{

[WebMethod(MessageName="vijay")]

public int abc()

{

return 100;

}

[WebMethod(MessageName="mukhi")]

public int abc(int i )

{

return i;

}

}

 

http://localhost/a.asmx/vijay

http://localhost/a.asmx/mukhi?i=123

 

In an asmx file, no two functions can share the same name. However, with the help of the MessageName property, a new name may be assigned to a common function.

 

The first abc function in the asmx file is named 'vijay', whereas, the second one is named 'mukhi'. Therefore, the first url contains 'vijay', and not 'abc'. The second function of 'abc' accepts a parameter. Therefore, the function abc named 'vijay' is ignored, and the new name assigned to abc is 'mukhi'.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

[WebServiceAttribute(Description="vijay mukhi")]

public class zzz : WebService

{

[WebMethod()]

public void abc()

{

}

}

 

aa.wsdl

<service name="zzz">

<documentation>vijay mukhi</documentation>

…..

</service>

 

Unlike the WebMethod attribute, which is placed on a function, the WebServiceAttribute is placed on a class. The Description property is employed to document the WebService. Therefore, at the end of the WSDL file, we encounter the last element service, containing the name of the class zzz. The Description property becomes the element documentation for the zzz service.

 

a.asmx

[WebServiceAttribute(Name="vijay")]

 

Modify the parameter of the WebServiceAttribute to the one depicted above, and observe the changes in the WSDL file.

 

In the WSDL file, since the name of the class is zzz, most elements begin with zzz. However, we would be able to modify the name of the service to 'vijay', by using the Name property. This would result in a change in the other elements too. The name of the proxy that is generated, would also change to vijay.cs, with the class name displayed as 'vijay'. Thus, we would be able to infuse a considerable amount of flexibility, by the use of attributes.

 

a.asmx

[WebServiceAttribute(Namespace="vijay")]

 

aa.wsdl

xmlns:s0="vijay" targetNamespace="vijay"

 

The WSDL file sets out with the definitions, which define and delineate a large number of namespace prefixes. This situation can be suitably altered, by using the Namespace property. The targetNamespace attribute ensures that a targetNamespace called 'vijay' is created, which relates to all the entities created in the file. You would have discerned that, the browser does not display any text on loading the asmx file, unlike the case of the earlier output.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using   System.Collections.Specialized;

using System.Web;

[WebServiceBinding()]

public class zzz : WebService

{

[WebMethod()]

public string abc()

{

string s = "";

int i;

NameValueCollection c;

HttpRequest r = Context.Request;

c=r.Headers;

string[] s1 = c.AllKeys;

for (i = 0; i<s1.Length; i++)

{

s = s + "Key: " + s1[i] + "=";

string[] s2=c.GetValues(s1[i]);

s =  s + s2[0] + ".";

}

return s;

}

}

 

 

Output

Key: Connection=Keep-Alive.

Key: Accept=*/*.Key: Accept-Encoding=gzip, deflate.

Key: Accept-Language=en-us.

Key: Host=localhost.

Key: Referer=http://localhost/a.asmx?op=abc.

Key: User-Agent=Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.0; .NET CLR 1.0.2914).

 

This book primarily converges around the concepts of SOAP and XML. Hence, we do not submerge ourselves any deeper into the details of the Webservice class. Nonetheless, we have presented an artless yet effective example, which highlights the influence exerted by the properties contained in the class.

 

It is possible for us to access every aspect of the web server, by using the WebService class. One such property in this class is the Context property, which is of type HttpContext. This property has a host of other properties of type HttpRequest, each prefixed with the word 'Request'. Moreover, there exists a member called Headers, which returns the headers received by a Web Server. The data type of this return value is a NameValueCollection object.

 

The object c' has a property called AllKeys, which returns an array of strings. The values contained in the array are the keys that arrive at the web server. A key is the word, placed before the 'equal to' sign in a name-value pair. With the assistance of a 'for' loop, every key in the array is accessed. Thereafter, using the GetValues function, the value of each key is returned.

 

Each key can have multiple values, but we have confined ourselves merely to the first value. The key and its corresponding value are placed in a huge string, and then, they are sent across. These values are displayed, when the asmx file is loaded in the browser.

 

 

Thus, by harnessing the abilities of the properties of the Context object, the information sent to the web server can be accessed with considerable ease.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz

{

[WebMethod()]

public int abc(int i , int j)

{

return i+j;

}

}

 

a.cs

public class zzz : System.Web.Services.Protocols.SoapHttpClientProtocol

{

public static void Main()

{

zzz a = new zzz();

string b;

b = a.abc(10,20);

System.Console.WriteLine(b);

}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute()]

public string abc(int i , int j)

{

Url = "http://localhost:8080/a.asmx";

object[] results = Invoke("abc", new object[2]{i,j});

return (string)results[0];

}

}

 

>csc a.cs

>a

 

The asmx file and the .cs file are analogous to the ones encountered in the earlier chapters. The function abc in the asmx file, returns the sum of the two ints that are supplied to it as parameters. In the client program, the function abc is called with the two values of 10 and 20. Thereafter, everything else works with clockwork precision.

 

Now, carry out a minor modification to the above program, by eliminating the attribute of SoapDocumentMethodAttribute. On doing so, the following exception is thrown:

 

Output

Unhandled Exception: System.ArgumentException: abc Web Service method name is not valid.

 

Thus, this corroborates our credence that, it is the SoapDocumentMethodAttribute that introduces code, when we are remoting functions from the client end.

 

a.cs

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(Action="sonal")]

 

Output

Unhandled Exception: System.Web.Services.Protocols.SoapException: System.Web.Services.Protocols.SoapException: Server did not recognize the value of HTTP Header SOAPAction: sonal.

   at System.Web.Services.Protocols.SoapServerProtocol.Initialize()

 

The first property that is employed with SoapDocumentMethodAttribute is 'Action'. It is used to set only the Http header SOAPAction, which has been added by the SOAP specifications. This header spells out the intentions of the SOAP request. The default value is http://tempuri.org, followed by the function name 'abc'.

 

The SOAP specification is not rigid with respect to the contents of this value. Therefore, firewalls can exploit this function to filter out unwanted SOAP requests. In our case, the server throws an exception, indicating the fact that it cannot recognize or comprehend 'sonal'. It is the Invoke function that triggers off the Exception. The server generates a SOAP fault, since it does not recognize the SOAPAction header at all.

 

 

a.cs

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(OneWay=true)]

 

Output

Unhandled Exception: System.Exception: Method zzz.abc can not be reflected. ---> System.Exception: One-way methods cannot have return values.

   at System.Web.Services.Protocols.SoapReflector.ReflectMethod(LogicalMethodInfo methodInfo, Boolean client, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter, String defaultNs)

 

The next property to be implemented is the OneWay property. Its value is set to 'true', although, its default value is 'false'.

 

By throwing an exception, it acquaints us with the fact that, the OneWay function cannot have a return value. The exception is generated by the ReflectMethod, and not by the Invoke function. You would have observed that, no bytes are visible in the Trace output.

 

a.cs

using System.Web.Services.Protocols;

using System.Web.Services.Description;

public class zzz : System.Web.Services.Protocols.SoapHttpClientProtocol

{

public static void Main()

{

zzz a = new zzz();

a.abc(10,20);

}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(OneWay=true)]

public void abc(int i , int j)

{

Url = "http://localhost:8080/a.asmx";

Invoke("abc", new object[2]{i,j});

}

}

 

SOAP response

HTTP/1.1 100 Continue

Server: Microsoft-IIS/5.0

Date: Wed, 17 Oct 2001 02:38:01 GMT

 

HTTP/1.1 200 OK

Server: Microsoft-IIS/5.0

Date: Wed, 17 Oct 2001 02:38:01 GMT

Cache-Control: private, max-age=0

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

Content-Length: 358

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:/

/www.w3.org/2001/XMLSchema">

<soap:Body>

<abcResponse xmlns="http://tempuri.org/">

<abcResult>30</abcResult>  

</abcResponse>

</soap:Body>

</soap:Envelope>

 

In place of 'formatted', set the trace output to 'unformatted', and take a look at the bytes that contain this header data.

 

The above example has no return value in either of the two functions, i.e. abc and Main. An HTTP response always starts with the HTTP version number 1.1 and a success or error code, followed by the description of the status code. For instance -

     200 is followed by 'OK'.

     404 is followed by 'File Not found'. 

     100 is followed by 'Continue'.

 

The status is followed by headers, such as- Date, Cache-Control, Content-type and length.

 

The OneWay property, as specified in the client program, indicates that the client would not wait for the web server to complete the processing of the Web Service method. Therefore, the client sends the header  "Expect: 100 Continue".

 

On receiving the request,  the server too first sends across an HTTP  header. Thereafter, it sends the entire SOAP payload, together with the reply.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz

{

[WebMethod()]

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(OneWay=true)]

public void abc(int i , int j)

{

}

}

 

SOAP response

HTTP/1.1 100 Continue

Server: Microsoft-IIS/5.0

Date: Wed, 17 Oct 2001 02:51:23 GMT

 

HTTP/1.1 202 Accepted

Server: Microsoft-IIS/5.0

Date:Wed, 17 Oct 200 1 02:51:24 GMT

Cache-Control: private

Content-Length: 0

 

An alternative approach would be, to set the Attribute OneWay on the WebService method, on the server. On doing so, the server will first send an HTTP/1.1 100 packet, followed by a "202 Accepted" response. This response packet, when received by the client, will ascertain that the client does not have to wait for the server to dispatch the result packet. However, in this case, there is no SOAP response at all.

 

Thus, the WebService will first deserialize the SOAP message, and then send the 202 response over. This is done with the primary aim of apprising the client about the fact that, the server is in receipt of the message, and has started processing it. Thereafter, the client will receive no further intimation of the activities taking place on the server. This is the reason why we have not specified any return values or parameters. However, if an exception is thrown, a return packet specifying the exception, would definitely be sent across.

 

In the first example of the asmx file, the function abc returns an int. However, in the a.cs file, the value is accepted in a string. By default, no data types are sent across. Thus, we need to be exceedingly cautious about the parameters that are dispatched or received, since an XML file is capable of incorporating only the textual data.

 

If you were to change the trace design to a 'formatted' trace, no return packet would be perceptible at all. Now, undo the changes made in the a.cs and a.asmx files, and revert them back to their original position, i.e. at the start of the attribute. The code contained in the .cs file is shown below.

 

a.cs

using System.Web.Services.Protocols;

using System.Web.Services.Description;

public class zzz : System.Web.Services.Protocols.SoapHttpClientProtocol

{

public static void Main()

{

zzz a = new zzz();

a.abc(10,20);

}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute

(ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]

public string abc(int i , int j)

{

Url = "http://localhost:8080/a.asmx";

object[] results = Invoke("abc", new object[2]{i,j});

return (string)results[0];

}

}

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz

{

[WebMethod()]

[System.Web.Services.Protocols.SoapDocumentMethodAttribute()]

public int abc(int i , int j)

{

return i+j;

}

}

 

SOAP request

<soap:Body>

<i xmlns="http://tempuri.org/">10</i>

<j xmlns="http://tempuri.org/">20</j>

</soap:Body>

 

SOAP response

<soap:Body>

<abcResponse xmlns="http://tempuri.org/">

<abcResult>0</abcResult>

</abcResponse>

</soap:Body>

 

Earlier, when we had sent a SOAP request, we had first specified an element called abc, which is the name of the function, followed by the names of the parameters. This was imperative, since the ParameterStyle property had a default value of 'Wrapped'. Moreover, the return value was depicted as zero. This option ensures that the parameters are wrapped within the method name, beneath the Body element.

 

When the value of 'Bare' is specified in the ParameterStyle, as an outcome, the method name is wiped out completely. These are the only two styles that are available.

           

a.asmx

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(ParameterStyle=

System.Web.Services.Protocols.SoapParameterStyle.Bare)]

 

SOAP response

<soap:Body>

<abcResult xmlns="http://tempuri.org/">30</abcResult>

</soap:Body>

Modifying the style to 'Bare' in the asmx file, results in an answer of 30. However, the abcResponse element is not visible in the output. You may repeat this process in the client program too.

 

a.cs

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

RequestElementName="abc1")]

 

SOAP request

<abc1 xmlns="http://tempuri.org/">

 

SOAP response

<abcResult>0</abcResult>

 

The RequestElementName property alters the name of the function. So, the function abc is now known as 'abc1'. Resultantly, the element name in the SOAP request packet also becomes abc1. Since there exists no function called abc1, no error is generated, but the answer has a value of zero.

 

a.cs

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

RequestNamespace="mukhi")]

 

SOAP request

<abc xmlns="mukhi">

 

SOAP response

<abcResult>0</abcResult>

 

Next, we alter only the RequestNamespace property to 'mukhi'. Yet again, no answer is obtained, since the function abc belongs to the namespace tempuri.org, in the asmx file.

 

a.asmx

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

RequestNamespace="mukhi")]

 

SOAP response

<abcResult>30</abcResult>

 

Now, if we were to modify the attribute in the asmx file, so that it may contain the same value, the correct answer would be obtained. It is so because, both the XML entities, i.e. the functions abc, belong to the same namespace of 'mukhi'.

 

a.asmx

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

ResponseNamespace="mukhi",ResponseElementName="vijay")]

 

SOAP response

<vijay xmlns="mukhi">`

<abcResult>0</abcResult>

</vijay>

 

The same set of rules is applicable to the return packet too. In the asmx file, the namespace and the name are both set to 'mukhi' and 'vijay', using the ResponseNamespace and ResponseElementName, respectively.

 

Ensure that the same attribute values are specified in the .cs file also. If this is not done, the SOAP response goes on to confirm that the changes have been implemented, however, the client gets thoroughly confused. It happens because, the client expects an abcResult within an abcResponse parent, in a particular namespace.

 

a.cs

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

ResponseNamespace="mukhi",ResponseElementName="vijay")]

 

Output

30

 

On introducing the same attribute to the client, the result of '30' is obtained. Thus, it would be a judicious move to effect similar amendments on both sides, the client side and the server, since they are generally located on disparate machines, which could be geographically separated by millions of miles.

           

a.asmx

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

Use=System.Web.Services.Description.SoapBindingUse.Encoded)]

a.cs

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

Use=System.Web.Services.Description.SoapBindingUse.Encoded)]

 

SOAP request

<?xml version="1.0" encoding="utf-8" ?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/encodedTypes " xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<types:abc>

  <i xsi:type="xsd:int">10</i>

  <j xsi:type="xsd:int">20</j>

  </types:abc>

  </soap:Body>

</soap:Envelope>

 

SOAP response

<?xml version="1.0" encoding="utf-8" ?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<types:abcResponse>

  <abcResult xsi:type="xsd:int">30</abcResult>

  </types:abcResponse>

  </soap:Body>

</soap:Envelope>

 

The client program and the asmx file on the server are now introduced to a property called Use, which is initialized to a value of 'Encoded', using the enum SoapBindingsUse. The only other value that can be assigned is 'Literal'.

 

The two values, 'Literal' and 'Encoded', have been determined by the WSDL standard. The Use property sets the parameter encoding for the SOAP payload.

 

The 'Literal' option encodes parameters, using a predefined XSD schema for each parameter, whereas, the 'Encoded' method uses the rules mentioned in Section 5 of the SOAP specification. To cut the story short, the Envelope element now has 6 namespaces, instead of the 3 earlier ones. The attribute encodingStyle, from the soap namespace, explicitly specifies a style encoding. We do not bump into any method with the name of abc, however, we do come across the method name, containing the 'types' namespace prefix, which refers to the URI of http://tempuri.org/encodedTypes.

 

Within the child elements i and j, we overtly specify a type, using the type attribute from either the xsd or XML Schema namespaces. The individual types that are used, are defined by the XML Schema world. Thus, by employing the encoding style, the process of transmitting the data types and the contents of the parameters, gets simplified. The return value also comports itself in a similar fashion. This encoding behavior is preferred over the default behaviour. It is because, the other end becomes cognisant of the data type that it has received.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz

{

[WebMethod()]

public void abc()

{

}

}

 

a.cs

public class zzz : System.Web.Services.Protocols.SoapHttpClientProtocol

{

public static void Main()

{

zzz a = new zzz();

yyy b = new yyy();

b.i=10;b.k=20;

xxx c = new xxx();

c.x = 100;

b.j = c;

a.abc(b);

}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute(

Use=System.Web.Services.Description.SoapBindingUse.Encoded)]

public void abc(yyy a)

{

Url = "http://localhost:8080/a.asmx";

Invoke("abc", new object[1]{a});

}

}

public class yyy {

public int i;

public xxx j;

public int k;

}

public class xxx

{

public int x;

}

 

SOAP request

<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<types:abc>

<a href="#id1" />

</types:abc>

<types:yyy id="id1" xsi:type="types:yyy">

<i xsi:type="xsd:int">10</i>

<j href="#id2" />

<k xsi:type="xsd:int">20</k>

</types:yyy>

<types:xxx id="id2" xsi:type="types:xxx">

<x xsi:type="xsd:int">100</x>

</types:xxx>

</soap:Body>

 

In the above C# program, a yyy object that contains two int members, i and k, is sent across. It also contains a class xxx member j. The xxx class has only one int x.

 

The yyy object is now passed as a parameter to the function abc. The asmx file neither accepts any parameters, nor does it return any values. As was mentioned earlier, this does not result in the generation of any exceptions.

 

The SOAP request is much more complex than before. A type abc is created, which uses a href to a type id1. The type yyy has an id of id1, and its type attribute refers to the type yyy, in other words, it refers to itself. In addition to this, there are three variables i, j, k, which are followed by their data types and content.

 

The salient point to remember is that, since j is of another type, there is an href to id2. The 'id2' is an id, i.e. a name for an xxx type, enclosing a parameter of type int, and encompassing the value of 100. This is akin to the methodology used to store types in a WSDL file. Using the Encoded style, the information about types can be sent over. Send an array over, and scrutinize the SOAP packet that is generated.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

public class zzz

{

[WebMethod()]

[System.Web.Services.Protocols.SoapRpcMethodAttribute()]

public int abc(int i)

{

return i;

}

}

 

a.cs

public class zzz : System.Web.Services.Protocols.SoapHttpClientProtocol

{

public static void Main()

{

zzz a = new zzz();

int j = a.abc(10);

System.Console.WriteLine(j);

}

[System.Web.Services.Protocols.SoapRpcMethodAttribute()]

public int abc(int i)

{

Url = "http://localhost:8080/a.asmx";

object[] results = Invoke("abc", new object[1]{i});

return (int)results[0];

}

}

 

SOAP request

<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<tns:abc>

<i xsi:type="xsd:int">10</i>

</tns:abc>

</soap:Body>

 

The last attribute that we touch upon is, the SoapRpcMethodAttribute. This attribute behaves in a manner similar to the attribute mentioned above, apart from the encoding style, which is 'Encoded' in this case. Thus, it is the SOAP payload that carries the type information and the content. Most of the explanations rendered above, are equally relevant in this context too.