Passing reference parameters in WebMethods
Passing parameters by reference is a programming concept found in most of today’s object-oriented languages. In C#, we can pass reference parameters to a method using the ref modifier. The parameter will not contain a copy of the value, but a reference to the same storage location used by the variable in the calling code. So, a change of value of the reference parameter within the method will be reflected in the original variable after returning from the method. OK, this works fine if you are using a single machine. Mapping this concept to Web services presents a challenge because you’re not dealing with memory storage locations anymore. Web service invocations typically span process, machine, or organizational boundaries. When you invoke a Web service operation, you’re generating a SOAP message that’s transmitted across the wire to another application. The service then returns a response through another SOAP message.
Consider a WebMethod that does not contain any reference parameters:
[WebMethod]
public int AddNum(int x, int y)
{
return x + y;
}
If you invoke this operation, supplying the value of 3 for x and 5 for y, you’ll get the following SOAP response message:
<soap:Envelope xmlns:soap=""> <AddNumResult>8</AddNumResult> </AddNumResponse> </soap:Body> </soap:Envelope> Copy Code
Let’s modify the signature to make x a reference parameter and change the implementation to increment x‘s value before returning:
[WebMethod]
public int AddNum(ref int x, int y)
{
return x++ + y;
}
Now, when you invoke this operation using the same values as before, you’ll get the following SOAP response message:
<soap:Envelope xmlns:soap=""> <AddNumResult>8</AddNumResult> <x>4</x> </AddNumResponse> </soap:Body> </soap:Envelope> Copy Code
Notice that x is returned in the response message along with the result. The WSDL file generated by the WebMethod framework contains the XML Schema definition (shown in Figure 1) to describe the elements found in the request and response messages. When you generate a proxy class from this WSDL definition, the .NET Framework is smart enough to figure out that since x is found in both the request and response messages, it can be represented in C# as a reference parameter in the generated proxy class. So, the generated proxy class in this case will contain a method that looks like the following (attributes omitted):
{
object[] results = this.Invoke(“AddNum”, new object[] {x,y});
x = ((int)(results[1]));
return ((int)(results[0]));
}
I came across WebMethods where parameter is passed as ref. But is this a good practice?
//Option1 with ref
[WebMethod]
public void Transaction2(ref Test test )
{}
As opposed to writing
//Option2
[WebMethod]
public Test Transaction1(Test test )
{}
But we should be aware that when we do like this in WebMethod it does not work the same as normal programming concept where a ref points to the same storage location of the calling variable.
If we look carefully in the Proxy that .Net Generates we will find the followings:
//Option1 with ref
public void Transaction2(ref Test test) {
object[] results = this.Invoke(“Transaction2″, new object[] {
test});
test = ((Test)(results[0]));
}
as opposed to
//Option2
public Test Transaction1(Test test) {
object[] results = this.Invoke(“Transaction1″, new object[] {
test});
return ((Test)(results[0]));
}
here the result is casted back to (Test) and value is assigned to the ref variable.
If we look at the soap response of both Transaction1 and Transaction2 we find pretty much the same response, and Test object is created as part of the Response with its value.
//Option 1 with ref
<?xml version=”1.0″ encoding=”utf-8″?>
<soap:Envelope xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:soap=”http://schemas.xmlsoap.org/soap/envelope/”>
<soap:Body>
<Transaction2Response xmlns=”http://tempuri.org/”>
<test>
<input>string</input>
<output>string</output>
</test>
</Transaction2Response>
</soap:Body>
</soap:Envelope>
as opposed to
//Option 2
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Transaction1Response xmlns="http://tempuri.org/">
<Transaction1Result>
<input>string</input>
<output>string</output>
</Transaction1Result>
</Transaction1Response>
</soap:Body>
</soap:Envelope>
Though both the options results in similiar result still its strongly recommeded is to use a single class to encapsulate all the output parameter (if possible also input parameters). The reason is mainly considered from webservice’s interoperability. Normally webservices are designed to be exposed to external systems and possibly it will be called from multiple heterogenous client platform. Also ref is not supported by many platforms. For example if I am not wrong even in the .Net world currently we cannot call a webmethod implemented with a ref parameter for the MS Ajax.Net implementations.