|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionBecause of the stateless nature of the HTTP protocol a web server considers every request as a new one. This means that, if you want to track a series of related calls, you must establish a way of identifying if the current request is a new request or is related to another request. One way of doing that is to generate a token for the first request and then reuse the same token for related requests. The token can be anything from a number to a complex object, the only important thing is that the token is guaranteed to be unique. If that token is sent with every request, then everything works just fine, as we can say for sure to which group the current request is a part of. We can do it the other way around too: the client makes a call with a unique token and, based on that token, the communication occurs. This can be implemented when a unique username is used as a token, for instance. However, another problem arises, with even greater importance. What if all of the requests are related to the same object? What if we need to call the method several times on the same object and the method modifies the object? We need a way of storing the object between calls so we can modify the object with each new call. This is what we will be talking about. Using the token concept, I will describe a way of maintaining object state between sequent calls to the same object. The ideaThere are several ways of implementing this functionality. I will discus only two of them in this article. The idea is common to both ways, what differs is the implementation details. Let’s assume that we use the approach when the client uses a username for a token and makes a request to a web service. The idea: There is a list of all the tokens that previously made the request. When the request is made, the web service retrieves the token from the parameters of the request and compares it to the list. If the token is not found there, then this is the first request made for that token, and a new object is created for that request. The token is added to the list of tokens. If the token is found in the list, then this is a sequent request, and the object is available. The object is then retrieved. It will contain the current data (the data modified by the last request). Now we have the object (newly instantiated or retrieved). We can now use the object and call the methods we need. After we are done using the object, it is time to store it away so it will be available when we need it again. Sounds complicated? Well, it’s not. Fortunately for us, there are already implemented systems that help us with the token list. In what follows, I will discuss two systems that are available for use with no extra effort: The Using the Application object of web servicesEvery ASP.NET web application (including web services) has a facility called the Application State. This facility, accessed via the A long discussion would be required about Session State and the ways to store it. Actually, you can use a State Server, or even a SQL Server to hold the State data. If you are developing large applications, this is the way to go. However, for smaller applications, these solutions are, most of the times, not necessary. I hope it is clear that the This solution is great; however, it does have a drawback: the state is not persistent all the way. When the server is rebooted, the state is lost. Also, the ASP.NET worker process might be recycled by the Internet Information Services (IIS). This means that, sometimes, you might end up losing the data you have inside the Programming using this facility is extremely simple, as you can see in the code below: public string MethodCall_ver1(int token)
{
UserDefinedClass d = null;
//If the token not found in the Application
//object, we retrieve it
if (Application[token.ToString()] != null)
{
d = (UserDefinedClass)Application[token.ToString()];
}
else
{
//if the token was not found then we create a new object
d = new UserDefinedClass();
}
//Call methods on the object
//We save the object into the Application object
Application[token.ToString()] = d;
//The service returns
return string.Format("{0}", d.something.ToString());
}
We only have to check if an object is stored at the location specified by the token. If it is not, then we instantiate a new object. After we are done using it, we store it in the This solution is great if you have requests that are closer in time to one another and you don’t care very much about losing the data. However, when you are interested in keeping the state between requests whatever happens, and don’t what to use additional servers, the solution presented below can be used. Using the File SystemThe file system is a great way of storing objects between system restarts. Also, even if the file system is arbores cent in nature, there still exists a way of uniquely identifying a file inside a folder: by using the file name. So, the token can be used as a file name. When the request comes, the method will search for a file with the name as the token. The idea remains the same, only the implementation changes. Instead of looking in the Fortunately for us, the .NET framework allows us to do just that, and very simple! The //We have a setting in web.config which tells
//us where should we store the files.
// The setting is called TemporaryDirectory
//Check to see if the file if the specified directory
//exists. If it does, this is not the first request and we retrieve it
if (File.Exists(string.Format("{0}{1}.dat",
System.Configuration.ConfigurationManager.
AppSettings["TemporaryDirectory"], id )))
{
//Get a FileStream to point to that file
FileStream sr = new FileStream(string.Format("{0}{1}.dat",
System.Configuration.ConfigurationManager.
AppSettings["TemporaryDirectory"], id),
FileMode.Open);
//Create an object used in serializing/deserializing objects
BinaryFormatter bf = new BinaryFormatter();
//deserialize the object
d = (UserDefinedClass)bf.Deserialize(sr);
sr.Close();
}
else
{
//if the file does not exist then we create a new object
d = new UserDefinedClass();
}
//Call methods on the object
//We serialize the object back to the file system
FileStream sw = new FileStream(string.Format("{0}{1}.dat",
System.Configuration.ConfigurationManager.
AppSettings["TemporaryDirectory"], id),
FileMode.OpenOrCreate);
BinaryFormatter abf = new BinaryFormatter();
abf.Serialize(sw, d);
sw.Close();
//The service returns
return string.Format("{0}", d.something.ToString());
The <add key ="TemporaryDirectory"
value="C:\Inetpub\wwwroot\WebServicePersistent\temp\"/>
This is all that needs to be done in order for us to have a web service that persists its state between requests. This solution has the advantage that the state is persisted even between system crashes and system reboots. This is a great thing. However, we have the problem of authorized access. The files stored on a server can be removed by people with not so good intentions. This means that, if the objects contain sensitive data, we have a breach. In order for this not to happen, we have to set the appropriate ACL (Access Control List) on the folder where we store the serialized objects and make sure that IIS does not serve them to anyone! Testing the solutionWell, to do that, we just have to call the web service repeatedly with the same token, and see how the something property continues to increment. Performance considerationWhile storing objects in the On the other hand, while using the file based approach, you incur a penalty for each read and write to the disk. However, the memory is only allocated when it is needed, so no DDoS. ConclusionIf you want to have persistent state between sequent calls to a web service, you can employ one of the solutions I presented. Either use the The In any case, the solution you decide to implement is entirely up to you and the technical requirements of the application you develop. Happy coding!
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||