ASP.NET State Hell

by msimpson 2/18/2008 5:48:00 PM

Let me begin by saying that despite ASP.NET's strengths, its state management leaves some things to be desired.  If you've read some of my other blog posts you might not be surprised to hear me say that... I'm known in my office for being an old codger (at 37) who complains about lots of things.

The first issue is that the state management mechanisms in ASP.NET mix the concepts of scope and lifetime.  It's true that there is a loose correlation between the two; for example, Application state is scoped to all users of a given application, and lasts for the duration of that application.  Session state is accessible to the session, and lasts for the duration of the session.  The third option, ViewState, is scoped roughly to the session (actually more narrowly), and lasts across multiple requests for a single form.  You could say it's scoped to the form, but I think it's useful to define it based on lifetime.

Now examine the statements above.  The phrases "application state" and "session state" are pretty intuitive... but "view state"?  That should have been named "form state", except for the inconvenience of wanting it for individual controls as well as the form.  The distinction between lifetime and scope is never made, perhaps because with only these three options, the distinction is somewhat moot.

But once you're aware of the distinction, other possibilities present themselves.  For example, why can't we have state that persists for the duration of a "business process" (across multiple forms), instead of for the lifetime of a session?  What about state scoped to multiple users - all administrators, for example?  Or state with a lifetime spanning multiple sessions?  All of these would be useful for certain scenarios.

For anything but the three supported options, you're on your own.  Web developers have gotten good at using all the various techniques at their disposal - for instance using cookies to preserve state across sessions, using page-level variables to maintain state during the processing of a single page, etc.  But basically, once you need more than what the three main state facilities give you, you're on your own.

So there's a learning curve issue here in that state is not accessed through a consistent mechanism - new developers must learn not only how to use Application, Session, and ViewState, but cookies, Cache, page variables, hidden HTML fields, HTTP context, thread-local storage, etc. etc. 

The problem is worsened by the fact that each of these mechanisms has implications relating to the physical implementation, so the developer has to worry about those too.  For example, using the logical concept of "state scoped to the form with the lifetime of the form" means using ViewState, which means sending data to the client and back on each request.  With the exception of Session, ASP.NET doesn't really give you any options when it comes to the physical implementation.

As if all that weren't enough, in a multi-tiered application, maintaining state should not be be the presentation layer's concern.  When the presentation layer maintains state, one of two things will generally happen:  either the presentation layer will need to pass state to the business layer, or the business layer will need to know more than it should about the presentation layer.  Both are bad.

Finally, none of the state mechanisms in ASP.NET really offer immutability as a way to address multi-threading issues.  This might or might not be considered a fault of the platform, but if it existed and were transparent it would be handy.

In summary, I think there are a number of problems with ASP.NET state management:

  • confusion of scope and lifetime;
  • limited state options;
  • management of state through many independent, inconsistent mechanisms;
  • dependence on the physical implementation of each mechanism;
  • blurring of lines between the presentation layer and business layer;
  • lack of immutability.

What can we do about it?  I propose a state manager that attempts to do the following:

  • manage state based on various combinations of scope and lifetime, providing options beyond what ASP.NET and related facilities offer;
  • expose state capabilities through a single consistent interface;
  • hide the underlying physical implementation of each type of state, and allow use of different implementations where appropriate;
  • explicitly support the business layer, and maintain a clean separation between the business layer and presentation layer.

As I envision it, this state manager would be a class in the business layer, with a limited set of interfaces for supporting "state providers" that would manage the actual state data.  The class would enforce serializability of state data; although this is not required for the underlying implementations of all state providers, requiring it up front preserves the ability to switch implementations.  All access to state data would occur through the class, probably through static methods.  The specification of supported state options, and the mapping of providers to those options, would be done through configuration. 

The state manager would (ideally) support notions of scope based on the following:

  • Application: accessible by all users of an application;
  • Role: specific to all users with a certain role;
  • User: specific to an individual user (note that this is NOT the same as session);
  • Session*: specific to all requests in a given session.  This has lifetime implications because the session is only valid for a certain length of time;
  • Business Process*: specific to requests associated with a given logical business process.  This also may have lifetime implications due to the finite length of the business process, but at any rate it's separate from session scope.  Consider multiple sessions associated with the same business process, for example;
  • Form*: specific to the processing of a given form, from initial entry (IsPostBack=false) to the user leaving the form.  Equivalent to ViewState;
  • Request*: specific to the processing of a given request.

*Has lifetime implications.

The state manager would support similar options with regard to lifetime:

  • Application: lasts the duration of the application;
  • Session: lasts for the duration of the current session;
  • Business Process: lasts for the duration of a logical business process, which may or may not span multiple sessions;
  • Form: lasts for the duration of processing of a given form, from initial entry (IsPostBack=false) to the user leaving the form.  Equivalent to ViewState;
  • Request: lasts for the duration of processing of a given request.

It might be useful to put the scope vs. lifetime options above on a grid.  Some combinations might be unworkable, but I think a surprising number of them would be useful.

To limit the knowledge the business tier would have of the presentation tier, an inversion-of-control pattern could be used.  Interfaces could expose state capabilities available in the presentation layer, without requiring a direct reference to the System.Web assembly.  The presentation layer would pass a reference to a class (or classes) in that layer that implement the appropriate interfaces, allowing the state manager to use it to take advantage of things like ViewState.

A key goal here is divorce the logical concepts of state from their physical implementations.  The underlying implementations will always impose constraints - for example, storing session state in the database will make it difficult to know when the session ends.  But when enough providers are implemented options will become available.  In time, for example, I might be able to reconfigure the app to store form state (ViewState) on the server rather than sending it to the browser, without having to touch a line of code.

Sure would be nice :-)

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , , , , , ,

Software

Related posts

Comments

2/19/2008 4:59:36 AM

Clay

Always enlightening. Thanks!

Clay gb

2/24/2008 6:43:37 AM

Josh Gough

Mike, great post! Some comments on this. In ASP.NET 2.0, there is also "Control State", which technically is part of ViewState, but disabling ViewState does not disable Control State:

msdn2.microsoft.com/en-us/library/1whwt1k7.aspx

I am also wondering about Windows Workflow Foundation for you Business Process level state. Check out these articles and interviews for more information on that:

Long article: http://www.odetocode.com/Articles/465.aspx
Links to other resources and interviews: weblogs.asp.net/.../...ws-Workflow-Foundation.aspx

The nice thing about WF here is that it is actually not tied to ASP.NET, but can be used by any front end client.

Here is a quote from the OdeToCode article:

"We'll be making use of the WF SQL Persistence Service. Why? Well, it may take days or weeks for an order to move from the "Open" state to the "Completed" state. We can't rely on the web server staying up 100% of the time for weeks on end, or having enough memory to keep millions of order workflows in RAM. We need a place to save our workflows, and this is the job of a workflow persistence service. If you want more details on the SQL persistence service, see my article on "Hosting Windows Workflow".

In short, when our workflow reaches a point where it has nothing to do but wait for an event to arrive, the workflow runtime will see the workflow is idle and ask the persistence service (if one is configured) to take action. The SQL persistence service will serialize the workflow and shove the resulting bits into a SQL Server table. The service can then unload the workflow instance from memory. Weeks later, when a new event arrives (like the order finally shipped), the WF runtime will ask the persistence service to rehydrate the workflow. The runtime can than deliver the new event to the workflow and the workflow can resume execution. "

It takes him a long time to actually get to ASP.NET, and his conclusion is:

"Joining Windows Workflow and ASP.NET into a testable, flexible, maintainable application requires a bit of work, but the same could be said for almost any technology. What have we gained with WF? We've gained transparency in the sense that any developer, or even business person, can look at our workflow model in the workflow designer see how an order moves from Open to Completed. We have a UI that is driven by this model, and that will prevent users from accidently shipping a processed order. Although we haven't talked about the WF tracking service, we can instantly record a history of execution for each order by simply configuring this service into the runtime. We have automatic support for our long-running order processing by virtue of using the WF SQL persistence service. There are also a host of WF features we haven't taken advantage of, like using a WF Policy activity inside our state machine to execute a set of declarative business rules to validate an order."

It does seem like a lot of steps and code, but it does offer a way to maintain state across logins, for long-running business processes. Then again, simply storing something in the database and using status codes will basically achieve the same thing. Though, I guess the other nice part is having a visual designer and a "standard" approach to creating this workflows.

Take care,
Josh

Josh Gough us

Add comment


(Will show your Gravatar icon)  

  Country flag





Live preview

8/27/2008 4:47:01 PM

Powered by BlogEngine.NET 1.2.0.0
Theme by Mads Kristensen


Calendar

<<  August 2008  >>
MoTuWeThFrSaSu
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar

Pages

    Recent posts

    Recent comments

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright 2008

    Sign in