Vous êtes sur la page 1sur 6

Managing State in Web Services

Using session objects is always a good option for maintaining per user data. But the
case of web services is different. In real life, Web services may be called thousands
of times a day (for example, a web service maintained by Railway administration for
seat reservation). In such cases, keeping per user data in the webserver would be a
bad approach. If you have heard the term PARSSeM, there would be violations of
different parameters then. We would need to adopt some other approach.

In this article, I would focus on how session data can be maintained by web services
. Besides, I would describe using Application object in web services. Using
Application state object is always an easy and less resource consuming option
because it does not deal on per user basis.

How can you use Session State Object?

In web applications, you would use session object like:

Session["Userid"] = input_id;

And for retrieving,

String user_id = (String) Session["Userid"]

Let say, we want to check how much time our business logic code in seat reservation
web service took while fulfilling requests. The code for time spent calculation would
be included in the same web service.

Listing 1.1 defines this service:

using System;
2) using System.Web;
3) using System.Web.Services;
4)
5) namespace WebBook
6) {
7) public class Reservation : System.Web.Services.WebService
8) {
9)
10) [ WebMethod (EnableSession = true) ]
11) public void ReserveSeat ()
12) {
13) DateTime init_value =
System.DateTime.Now;
14)
15) // business logic for seat reservation
16) DateTime final_value =
System.DateTime.Now;
17)
18) // using Application State object. Would
explain it later
19) int total_requests = 0;
20) total_requests = (int)
Application["requests"];
21) total_requests = total_requests +1;
22) Application ["requests"] =
total_requests;
23)
24) // Updating Total time spent in session
25) TimeSpan timespan1;
26) Object Session_time = Session["Time"];
27)
28) if (Session_Time != null)
29) {
30) timespan1 = (TimeSpan) Session_time;
31) }
32) else
33) {
34) timespan1 = new TimeSpan (0,0,0,0,0);
35) }
36)
37) timespan1 += final_value - init_value;
38)
39) Session["Time"] = timespan1;
40)
41) [ WebMethod (EnableSession = true) ]
42) public String TotalTime()
43) {
44)
45) if (Session["Time"]==null)
46) return new
System.TimeSpan().ToString();
47) else
48) return ((System.TimeSpan)
Session["Time"]).ToString();
49) }
50)
51) }

Analysis of Listing 1.1

The method ReserveSeat() do two things: Implements the business logic for
reserving a seat and calculates the time spent while reserving seat(s). Before
executing the business logic, it notes the current system data and time and at the
end of execution, it again records the same. So, we can now calculate the time spent
during execution of seat reservation code. Since we were supposed to calculate all
the time spent till now by different users, we would take the previous Time value in
the session variable and add it with newly calculated value. The other function
TotalTime() returns the time spent so far.

The problem:

Web services can be called from web forms as well as console applications. But
manipulating session object in the same way as we do in other web applications can
create problems here.
If you call the Seat Reservation web service from a web form, you would receive
accurate results as long as cookies are enabled in your browser. If the cookies are
disabled, you would not see correct results. I would explain shortly why it happens.

If you call this service from a console application, again the same problem of
incorrect results would appear. You write a client console application like this:

Listing 1.2

1) using System;
2) using System.Net;
3) using WebBook.localhost();
4)
5) namespace WebBook
6) {
7) public class ServiceClient
8) {
9) public static void Main()
10) {
11) // Using the Reservation class
function
12) Reservation res_obj = new
Reservation();
13) res_obj.ReserveSeat();
14) res_obj.ReserveSeat();
15)
16) Console.WriteLine ("Total Time
spent is:" +
17) res_obj.TotalTime());
18) }
19) Console.ReadLine();
20) }
21)
22) }

If the total time spent for one time execution of function ReserveSeat() is 1 second,
can you guess what should it display? Most probably, you would say: "Total Time
spent is 00:00:02" but it would display "Total Time spent is 00:00:00". The problem
is explained below:

To keep track of user sessions, ASP.NET uses browser cookies. When a browser
accesses a site, a cookie and a session Object is created and session ID is stored in
the cookie. Upon every subsequent access, this cookie is used to send Session ID to
the webserver which contains user’s session data (that is why, if a web service
has thousands of clients, its webserver resources may be consumed quickly). The
problem is, not all web browsers enable cookies. Also, console applications do not
use session cookies. So using a session object is not possible in these cases.

Solution:
There is a two step solution to this problem.

1) As I said, many clients would not use cookies. However for those that use
cookies, disable them. This is achieved by making a simple change in web.config file:

<configuration>

<system.web>

<compilation defaultLanguage= "C#" debug= "true" >

<session cookieless = "true">

</system.web>

</configuration>

2) We should force ASP.NET to seek some alternative solution for session handling.
In the absence of cookies, ASP.NET uses a technique called "URL Munging". In this
technique, session ID is placed in the url of the web service when the first method
call is made. For example, in this case, we can have something like:

http://localhost/WebBook/(fdsjkalkjfal45kajs2)/Reservation.asmx

There is another issue: This new redirected URL will cause an exception in console
application. Ignore the cause of this exception . Below is one way to recover from
exception and generate the accurate results.

Listing 1.3

1) using System;
2) using System.Net;
3) using WebBook.localhost();
4)
5) namespace WebBook
6) {
7) public class ServiceClient
8) {
9) public static void Main()
10) {
11) // Using the Reservation class
function
12) Reservation res_obj = new
Reservation();
13) // Now, We handle the exception
that arises in console
14) // application.
15)
16) try
17) {
18) res_obj.ReserveSeat();
19) }
20) catch (WebException e)
21) {
22)
23) // This catch code would always
execute because of the
24) // exception. The exception message
e would tell us the
25) // munged redirected url.
26)
27) String message = e.Message;
28)
29) // Since the message contain
something like "Object moved to
30) // <a href ' " We would search
this string in the error
31) // message
32)
33) String to_search= "Object moved to
<a href ' ";
34) int desired_pos = message.IndexOf
(to_search);
35)
36) // check if string exists in error
message or there is some
37) // other exception
38)
39) if (desired_pos > 0)
40) {
41)
42) // Extract the message now. Message
to be extracted from
43) // start of message to 500
characters ahead, You can choose
44) // to even more if message length
is more than 500
45)
46) String extracted_message =
message.SubString (desired_pos
47) + 500)
48)
49) // Extract the url from the
extracted message.
50) // We would split the string using
the ' character. The url
51) // would be the 2nd element
52)
53) String[] broken_message =
extracted_message.Split ('\'');
54) String url= broken_message[1];
55)
56) // Now, lets redirect to access the
right page and to see the
57) // effect of session object.
58) res_obj.Url = "http://localhost "+
url;
59) }
60)
61) else
62) {
63) // Some other exception
64) throw e;
65) }
66)
67) }
68) // Now these calls would generate
right results
69) res_obj.ReserveSeat();
70) res_obj.ReserveSeat();
71)
72) Console.WriteLine ("Total Time
spent is:" +
73) res_obj.TotalTime());
74)
75) }
76) Console.ReadLine();
77) }
78) }

When you make a client like Listing 1.3, you would get something like:

Total Time spent is: 00:00:02

Using Application State

Please refer to Listing 1.1 and see Line 18-22. The application object can be used
with the same ease in all web services as is used in other web applications. If you
want to calculate the average time for processing of one seat reservation request,
you can do so by dividing the output of TotalTime() function in Listing 1.1 to the
"requests" variable in Application object which counts all the requests made.

Summary:

• The use of Session object in web services is debatable.


• ASP.NET use cookies to keep track of sessions.
• Therefore, Session handling is not possible in console applications and web
browsers having cookies disabled.
• One possible solution is to disable cookies so that ASP.NET may use the
technique "URL Munging". In this technique, it appends session ID to the url
on first call.
• Usage of Application object is easy and can be done with the same logic as
web applications.

Vous aimerez peut-être aussi