Introduction
Web Services allow several operations to be published at a single end-point.
However, there may be a scenario where more than one operation may be required to be invoked, in a specific order, and an internal state needs to be maintained.
Scenario
Let’s take a concrete but simple example for demonstration.
There is a service called MathService
that publishes two operations Add
and Subtract
.
Add
operation requires that two integers are parameters and returns an integer – result of addition of values to the two parameters.
Subtract
requires just one parameter. It returns the difference between the result of last operation - addition or subtraction - (by the same client) and the value of parameter passed.
As an example, first call to Add
with values 4 and 5 returns 9. Then, a call to Subtract
with a value of 3 would return 6. Next, a call to Subtract
with a value of 10 would return -4 and so on.
How can this web service be modified to maintain the state?
Solution
For extreme cases, one must look at the Web Service Transactions Specification.
I am providing a quick-heal solution. But the same idea can be used in any web services that require maintaining states – not only by one service but multiple services.
I would modify the Add
operation to return two items – the result of addition and a unique token.
I also modify the Subtract
operation to take an additional parameter – a token that would be used to internally track the data.
It is required since for every operation invocation, a new instance of the class representing the web service is created. Using the unique token, the data would be cached on the server side.
The implementation of the cache is what remains in question. I am using an inbuilt implementation for the cache for MathService
– using the HttpRuntime
Cache
. Persistent caching may be provided using databases and other dependencies.
[WebService(Namespace="http://www.edujinionline.com/ns/samples/webservices/")]
public class MathService : WebService
{
[WebMethod]
[return: XmlElement("result", typeof(int)),
XmlElement("token", typeof(string))]
public object[] Add(int x, int y)
{
int z = x + y;
string token = Guid.NewGuid().ToString();
Cache cache = HttpRuntime.Cache;
cache.Insert(token, z, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(30));
return new object[] { z, token };
}
[WebMethod]
[return: XmlElement("result", typeof(int))]
public int Subtract(int y, string token)
{
Cache cache = HttpRuntime.Cache;
object obj = cache[token];
int x = 0;
if(obj != null)
{
x = (int) obj;
}
int z = x – y;
cache[token] = z;
return z;
}
}
The web service is ready to be deployed and tested.
You can download the source code and test client to see how all this works!
The output may appear as shown below:
You can also visit web-service related blog at Eduzine© - electronic technology magazine of EduJini, the company that I work with.
Summary
One can have stateful services without going into the nitty-gritties of Web Service Transactions, or using WSE to modify the Head
of the Envelope
or rely on cookies that some enterprises disallow.
Note
You may need to update the web reference for the web-service in the client. I used 'File System' for ASP.NET application and the Web-Server was on port 1073. Update the reference for your case.