- From: Clemens Vasters <clemensv@newtelligence.com>
- Date: Fri, 18 Jan 2002 20:24:15 +0100
- To: "'xml-dist-app'" <xml-dist-app@w3.org>
I thought this may be interesting here as well, although it's somewhat ASP.NET related... -----Original Message----- From: Clemens Vasters [mailto:clemensv@newtelligence.com] Sent: Friday, January 18, 2002 7:19 PM To: 'dotnet@discuss.develop.com' Subject: Why web-style session state management doesn't work for web services, methinks [First, sorry for the cross-posting on DOTNET/SOAP, but I really didn't know where this fits best. Also, sorry for the abuse as my mind dump.] I am currently writing something about web services performance and part of the server-side performance consierations is, of course, state management. Now, when I was writing that section this morning, I suddenly realized why I always had this very bad gut feeling about using something like cookie-based state management (as ASP.NET does it) for web service state management. Here's what I think and it'd be great to hear some opinons. I can't follow all of the discussions here (who can?) so this may even have been discussed, but I didn't see it. Simple technical problems first. The classic approach to state management with HTTP is to pass some kind of identifier to the client that is returned in a subsequent request and allows the server to reassociate the request with the buffered session state. There are three ways to do this: Cookies, URL injection and soring references in the response body: (a) Use of cookies: From the start, cookies aren't covered by RFC2616 (HTTP 1.1), but by RFC2964 (HTTP State Management) and entirely optional. If a client receives a cookie that the server uses for managing state, the client can just completely ignore that cookie and still play fair by all written rules. While perfectly legal, this will break cookie based state management. (b) Use of URL injection: It's pretty obvious, but I am still going to say that the ASP.NET style cookieless sessions that work by injecting information into returned reference URLs won't work, because a web service client simply doesn't receive reference URLs to click on. (c) Response body: The most obvious place would be a SOAP header. Perfectly doable, but there is no widely circulated proposal for this (or I didn't look hard enough) and every approach is therefore proprietary. My very special ASP.NET problem with this: ASP.NET's HTTP session model is a closed shop. Most classes are private to the HttpModule that sits in the ASP.NET pipeline and filters/injects the cookie and/or URL from/into the in/outbound stream. So if I wanted to relay some sort of session cookie via SOAP header I'd have to roll my very own session management as well. This is unless I would write an HTTP module that would sit before the ASP.NET session manager and would parse and peel the session-id from the SOAP header and set it as an HTTP Cookie header for ASP.NET to pick up. On the way out, I'd have to grab the ASP.NET session cookie and stick it into the SOAP header. That'd be very nasty, because that'd require SOAP processing entirely outside of the web services infrastructure. So, in essence, if the client chooses to ignore cookies, the state management issue doesn't really look good anywhere at this point. That were the technical "status quo" issues. Pretty bad, but manageable in some ways and by convention. ---- Now, thinking about this, I have come to the conclusion that the web-style approach to state management using any of these three techniques is (!) utter nonsense (!), because they are all based on a completely wrong assumption. They still assume that the client is completely dumb and just smart enough to push back an opaque value that the server is providing. It is also based on the assumptions that the transport is HTTP and that web service call sequences are never cascading. Here's the (somewhat lengthy and right off the top off my head == confusing) reason why I think that's wrong: Given I have some kind of web service proxy for a web service interface and a call sequence A->B. The call sequence happens to establishes some sort of server state in an initial call to A (for some good and justifiable reasons) and that state is required to execute B. When A is called a second time, the state is not newly initialized but updated taking current state information into account. This is perfectly okay as long as the client stays in the same context. If the client switches contexts (in the sense of "business logic contexts"), it will want a new context (freshly initialized server session if you will) to be set up on a call to A. How's that currently done? It works because when establishing a new logical context you will create a new proxy that doesn't know about the cookies that were sent previously and therefore ASP.NET will create a new session and hand out a new session cookie. So, the ASP.NET proxy ("Add Web Reference" proxy) does indeed keep record of a remote object identity through its caching of cookies. The remote object is the stored state. If you want a new object, create a new proxy. So far, so good. Given I have a web service proxy for a web service interface and a call sequence A->B. The web service establishes some sort of server state in an initial call to A and that state is require to execute B. The implementation of A calls the method X of another web-service with a call sequence X->Y, where that web service establishes some sort of server state in an initial call to X and that state is require to execute Y. Now, A calls X, B calls Y. Y depends on the state of X established by the call from A. Because A and B are stateless methods and the web service class is in fact discarded between calls, B will build a new proxy and the state of the secondary web service will no longer be available, because the original proxy didn't live to remember the cookie. Bummer. While this is just an effect of statelessness in ASP.NET and there are technical workarounds that I could figure, I could just as well make the scenario quite a bit worse and virtually unmanageable. The question that will remain is: "Can any web service server implementation make a correct judgement about the context of its invocation based on traditional, web-style state management means?" I say: The only instance that can make any proper judgement about call contexts and about how and when state needs to be managed is the topmost caller. If the initial caller would tell A that it is in context "C" and A would pass this on to X, the same context "C" could be used by B and Y to retrieve their state information later on, independent of implementation issues and even transport. I think it's fundamentally wrong to have any web service server decide on state identity in a stateless environment where cascaded service request can occur. The topmost client is the only instance can decide about logical context boundaries and therefore it must be the instance controlling state management boundaries. Therefore it's my current state of opinon, that a SOAP header is required that defines the current call context and the context origin that must be understood by all state managing services. To illustrate my point: <ctx:context contextId="uuid:0B4E71D0-5383-4db2-9BA5-EE17B7E46627" contextExpires="2001-18-01T23:00:00+01:00" soap:mustUnderstand="1" xmlns:ctx="urn:schemas-newtelligence-com:soap:contexts"/> * contextId is an URI that MUST be globally unique and that identifies the logical call context originating from the topmost web service client. * A web service server MUST understand the context and associate all session state with the contextId value. * If a web service client is itself part of a web service server implementation, it MUST NOT create a new context, but MUST pass the contextId and the contextExpiration on to its server, if the server implementation received a context header. * A web service server MUST keep the session information associated with the context until the time indicated by contextExpires. If the server decides that the time-span between "now" and the contextExpires time is too long (to avoid DoS) it MUST fail with ctx:Client.ContextTimeoutNotAccepted [this is a client provoked error] * A server SHOULD allow a timespan of 10 minutes for context expiration. * If the context has expired (independent of whether the information is still available), the server MUST fail with ctx:Client.ContextTimoutExpired [this is a client provoked error] * The context owner (topmost client) MAY adjust the contextExpiration value into the future at each call. In essence I am saying that the identifier with which all state must be associated throughout the web service call hierarchy must be defined by the topmost caller. Shoot me! :) Clemens
Received on Friday, 18 January 2002 14:26:12 UTC