Web apps and scopes
In a classical webapp (ie not using continuations) there's three scopes : application, session and request. The application scope is not that much used except for architectural purposes and the request scope is only useful for data only relevant to the computation at hand. We are left with one single choice: session scope. Consequently we cram in session scope everything not worth of being stored in database.
Too much shared state!
Okay, alternatively you can store the state in the client. There's two ways:
A webthread is the succession of pages accessed through forward browsing. A webthread can be forked (eg by opening a link in a new tab).
First of all, I have to offer a solution to the state storage responsibility problem. The state is stored on the server but an id identifying the state is stored in the browser. Where to store this id? Url or hidden form field? (Cookies aren't an option, they are shared between windows.) My bet goes on the url.
So I propose to use pathes of the following form: /[state-id]/[applicative-path].
My core design idea is to link states and, hence, when looking up for a property you have to look in the current state and, if the property is not found, you follow the links 'til you find the property... or the end of the webthread.
How to link the states? Two solutions: use the Referer http header or rewrite (client-side or server-side) all the urls in the served page.
(I'll let the reader to develop the url rewriting way-of-link as an exercise.)
The server receives the /preferences request with /0001/home as a referer. The server creates a new state (0002), and links 0002 to 0001 (0002 "inherits" all the properties of 0001). The server redirects (302) the client to /0002/preferences.
The client requests /0002/preferences.
The server does the actual requested processing and returns its response.
Rinse and repeat.
(If you request /preferences from /0001/home again, you'll be redirected to /0003/preferences)
Et voilà! You've got webthreads and their associated scopes!
Here you go Eric, you've got the "interactive page" scope we talked about some times ago!
Now it's up to the implementer to refine this mechanism and to define a state invalidation policy (a hard job).
Too much shared state!
Okay, alternatively you can store the state in the client. There's two ways:
- on the one hand, hidden fields and form submissions (through post methods); as far as I know, it's the current design of JSF and Asp.Net (Eric, Olivier? someone to confirm?).
- on the other hand, use the url stupid!... and end up passing 3k urls to the user.
So what?
Here, on Eric's request, I'm going to document an idea of design which I've never written down: webthreads.A webthread is the succession of pages accessed through forward browsing. A webthread can be forked (eg by opening a link in a new tab).
First of all, I have to offer a solution to the state storage responsibility problem. The state is stored on the server but an id identifying the state is stored in the browser. Where to store this id? Url or hidden form field? (Cookies aren't an option, they are shared between windows.) My bet goes on the url.
So I propose to use pathes of the following form: /[state-id]/[applicative-path].
My core design idea is to link states and, hence, when looking up for a property you have to look in the current state and, if the property is not found, you follow the links 'til you find the property... or the end of the webthread.
How to link the states? Two solutions: use the Referer http header or rewrite (client-side or server-side) all the urls in the served page.
(I'll let the reader to develop the url rewriting way-of-link as an exercise.)
Synopsis
The client is at /0001/home where (0001 is the state id) and requests /preferences.The server receives the /preferences request with /0001/home as a referer. The server creates a new state (0002), and links 0002 to 0001 (0002 "inherits" all the properties of 0001). The server redirects (302) the client to /0002/preferences.
The client requests /0002/preferences.
The server does the actual requested processing and returns its response.
Rinse and repeat.
(If you request /preferences from /0001/home again, you'll be redirected to /0003/preferences)
Et voilà! You've got webthreads and their associated scopes!
Ajax (and other page refreshing solutions) bonus
The internal processing (ajax and reloads) of a page can benefit from having a persistent state associated to the page: all such requests take place in the same state, internal requests MUST NOT spawn new states.Here you go Eric, you've got the "interactive page" scope we talked about some times ago!
Now it's up to the implementer to refine this mechanism and to define a state invalidation policy (a hard job).