Tuesday, March 10, 2015

Using ref parameters in WCF service contract

Actually it didn't make sense to have ref parameter in service calls as most of the cases service runs in different process and client don't get reference to the server memory address. But still WCF supports it.

I never thought it will work until I saw this in one of the production applications. We were re-factoring a legacy code base and could see one operation contract with ref keyword. Initially we thought that service itself is not in use and can delete it. But my colleague was sure that it works. So decided to do a sample as running the app and finding out which functionality in that giant app is going to use it takes more time. Below is the PoC we did.

WCF Service contract

Created service contract with 3 operation contracts

    [ServiceContract]
public interface IMathServiceWithRef
{
    [OperationContract]
    int GetSum(int number1, int number2);
    [OperationContract]
    Result GetSumAndAverageAsResultObject(int number1, int number2);
    [OperationContract]
    int GetSumAndAverage(int number1, int number2, ref int average);
}
[DataContract]
public class Result
{
    [DataMember]
    public int Sum { getset; }
    [DataMember]
    public int Average{ getset; }
}

WCF Service Implementation

Simple implementation as below

public class MathServiceWithRef : IMathServiceWithRef        
{
    int IMathServiceWithRef.GetSum(int number1, int number2)
    {
        return number1 + number2;
    }
    Result IMathServiceWithRef.GetSumAndAverageAsResultObject(int number1, int number2)
    {
        return new Result() { Sum = number1 + number2, Average = (number1 + number2) / 2 };
    }
    int IMathServiceWithRef.GetSumAndAverage(int number1, int number2,ref int average)
    {
        average = (number1 + number2) / 2;
        return number1 + number2;
    }
}

WCF Client proxy & Test class

Right clicked on the service reference section and added using the svc url. Used simple test project which already have service reference

        [TestMethod()]
public void WithNormalValues_ShouldSuccess()
{
    WCFService1.MathServiceWithRefClient client = new WCFService1.MathServiceWithRefClient();
    int average=0,sum = 0;
    //////////////////////////////////////////
    sum = client.GetSum(20, 10);
    Assert.IsTrue(sum == 30);
    //////////////////////////////////////////
    Result result = client.GetSumAndAverageAsResultObject(20, 10);
    Assert.IsTrue(result.Average == 15 && result.Sum == 30);
    /////////////////////////////////////////
    sum=client.GetSumAndAverage(20, 10, ref average);
    Assert.IsTrue(average == 15 && sum==30);            
}

And this worked as expected. Fiddler results below

Fiddler results

Simple Sum() call

Request XML
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <GetSum xmlns="http://tempuri.org/">
      <number1>20</number1>
      <number2>10</number2>
    </GetSum>
  </s:Body>
</s:Envelope>
Response XML
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <GetSumResponse xmlns="http://tempuri.org/">
      <GetSumResult>30</GetSumResult>
    </GetSumResponse>
  </s:Body>
</s:Envelope>

With ref keyword

Request XML
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <GetSumAndAverage xmlns="http://tempuri.org/">
      <number1>20</number1>
      <number2>10</number2>
      <average>0</average>
    </GetSumAndAverage>
  </s:Body>
</s:Envelope>
ResponseXML
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
      <GetSumAndAverageResponse xmlns="http://tempuri.org/">
        <GetSumAndAverageResult>30</GetSumAndAverageResult>
        <average>15</average>
      </GetSumAndAverageResponse>
    </s:Body>
  </s:Envelope>

As we can see in the fiddler the response xml just contains the ref value. But not as result. 

WCF communication protocols tested

Obviously there is no need to test using various protocols as WCF is more towards protocol independent in all most all the cases.

Still we tested in net.pipe and net.tcp protocols and it worked.

Why someone should use ref keyword in WCF operation contact

If someone is really lazy to create a DataContract class they can use this method. I don't see any other benefits.

Happy coding. 

No comments: