Dan Maharry

ASP.NET 4.0 Part 14, More Control Over Session State

by

Welcome to part 14 of my tour through ASP.NET 4.0. In this episode, we're going to look at two new features Microsoft have added to the way we can control ASP.NET session state. If you choose to use them, they will definitely improve the perceived performance of your session state provider and therefore your application.

Session Compression

Arguably the easiest way to improve session state performance is not to use it, or at least to put as little in it as absolutely possible. However, sometimes that's just not possible. Even some Microsoft teams use perhaps a bit more than they should - the Office Web team stick Word files in session state for example - so we're not the only ones who do it. The problem then is that performance suffers as session info runs over the network between the database storing the info and the web server and then onto our users.

The first of the new features in ASP.NET 4.0 is to make use of the compression features in .NET and apply them transparently to all the serialized session state on the fly as it goes between the web server and the out-of-process state server.

"Anecdotal evidence suggests that this [trade-off between CPU time for network bandwidth] provides reduction in size of between 33% and 66%." - Stefan Schackow, PDC 2009

All you need to do to switch session compression on is set the following config.

<configuration>
...
<system.web>
...
<sessionState compressionEnabled="true" ... />
...
</system.web>
</configuration>

Just to reiterate, session compression doesn't apply to in-process session state but applies equally to the SQL Server provider for out of process session state and the out-of-process state server provider. If you've never considered or simply never needed to work with an out-of-process state server, why not give it a try? Some say that they always go straight to out-of-process - your mileage may vary. Should you wish to investigate further, here are a few good links.

SetSessionStateBehavior

Ever wondered how ASP.NET actually determines whether session state should be used for a page? Me neither. All we really need to know is that we set a default for the Session State module in web.config - enabled, read-only or disabled and then use the @Page directive's EnableSessionState attribute to override that default as required.

However, this is all declarative. What we've been unable to do from v1 to v3.5 SP1 is to override and set the current mode for the session state server programmatically. This now changes in v4 where we can set a new value in the HttpContext that says what mode it should be. Simply create a new HttpModule and hook the BeginRequest event. It has to be this early so the change can be set and ASP.NET will notice the change.

public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(OnBegin);
}
private void OnBegin(object sender, EventArgs e)
{
HttpContext c = (sender as HttpApplication).Context;
c.SetSessionStateBehavior(SessionStateBehavior.Required);
}

The SessionStateBehavior enumeration has four possible values. Three of them - Required, ReadOnly and Disabled - set the state server mode and override the value of any EnableSessionState attribute in your @Page directive. However, the fourth value - Default - sets the state server mode to that declared in web.config and allows overrides from your @Page directives, just as it did in previous versions of ASP.NET.

In case you were wondering how session state does work, the session state module inspects the HTTP headers for each incoming request for a 'marker interface' which it then interprets as session state being required or read-only. If it's not there, session state is read as disabled. Hence the problem with setting SessionStateBehavior programmatically - the mechanism has to work over the top of those interfaces rather than manipulate them - they are interfaces so there is nothing to manipulate.

Summary

In this episode, we've looked at two new features of ASP.NET for dealing with session state servers - session compression and the ability to set their behavior programmatically. Touted as a post-RTM release, much like the new OutputCache providers mentioned in Part 13, Microsoft also plan to release a new partial session state provider which allows you to state which items in session state should be downloaded from state to web server for any given page being requested. However, that's for investigation after April 12. So for the meantime, happy coding!

ASP.NET 4.0 Part 13, A New Output Caching Provider Model

by

Welcome to part 13 of my tour through ASP.NET 4.0. In this episode, we're going to look at caching. One goal for .NET as a whole is to have it use a single caching framework. ASP.NET won't make use of this global framework until .NET 5, but in the meantime, v4 does see some much needed changes in System.Web.Caching that address its more major limitations when used against high-use websites.

Up until now, ASP.NET caching has been a one trick pony with its only storage option for cached items being in-process on the server which hosts the website doing the caching. This is fine for websites of a certain size, but once they need to be scaled up across web farms or web gardens, the in-process boundary makes this built-in caching functionality no longer useful. Indeed, the need for any alternative to memory-based, process-bound caching is anathema to the built-in facilities of ASP.NET 3.5-.

Changes to caching in ASP.NET 4.0 then are not so much about performance, but geared towards creating an extensibility point for caching and introducing the notion of an output cache provider. That way, should we so choose to do so, we can define our own mechanism for both control-level output caching and page-level (i.e. caching the HTTP Response as a whole) caching.

Constraints on your Custom Provider

One of the main reasons for providing an output cache provider model is to offer a way to have items in the cache stored outside of the worker process (and therefore the AppDomain) looking after your website.
However, with that barrier crossed and caching now taking place on disk, cloud, distributed cache etc, several issues arise which mean that some constraints must necessarily be placed on any output cache provider.

  1. Absolute expiration is supported on controls and pages that use custom ouput cache providers, but sliding expiration is not. Consider the case where five web servers are all talking to the same distributed cache. There's no way to keep that sliding expiration in sync across all five machines.
  2. File dependencies are supported but custom dependencies are not. Thus if you invalidate a page, all the supporting cache items for that page will also be invalidated, but there is no support for creating a dependency between cache and other types of object using a custom CacheDependency.
  3. Static substitution, also known as doughnut-hole caching, and output cache validation are supported but only with a static delegate. This is so the caching information can survive a process restart.  When an application restarts, there will at least be a serialized value that tells us what type to get and method to use to wire the cache back up again, because it's static.

With those constraints in mind, to create your own custom cache provider, you'll need to write a class that derives from the new System.Web.Caching.OutputCacheProvider class and overrides its Get, Set, Add and Remove methods. Gunnar Peipman has an excellent post detailing a simple sample implementation for you as a starting point.

Microsoft are also slated to release two output cache providers of their own (most likely via Codeplex) post .NET 4.0 RTM. One is a disk-based caching provider and the other targets AppFabric Caching (formerly known as Velocity), a distributed caching service.

Incorporating Your Provider Into A Site

Once you've created your custom cache provider, integrating it into your site is quick and easy. First, you'll need to declare it in web.config. ASP.NET 4.0 expands <system.web>\<caching>\<outputCache> for this purpose

<configuration>
...
<system.web>
...
<caching>
<outputCache defaultProvider="AspNetInternalProvider">
<providers>
<add name="CloudCache"
type="Sample.CloudCacheProvider, SampleCacheProviders"/>
</providers>
</outputCache>
</caching>
</system.web>
</configuration>

Setting up your new caching provider to provide output caching at a control-level is now very easy. A new attribute to a control's @OutputCache directive allows you to set the provider used declaratively.

<%@OutputCache Duration="360" VaryByParam="UserName" ProviderName="CloudCache" %> 

However, should you wish to set your new provider to cache at the page level you'll need to take a different route. Cache checking at a page-level takes place in the ASP.NET processing pipeline several stages before an instance of the Page class in question has been created, so declaring your required provider in the Page's @OutputCache directive would be several steps too late to influence anything. Instead, you'll need to override a new virtual method on the HttpApplication class called GetOutputCacheProviderName in a custom class or global.asax directly to make the change.

public class Global : System.Web.HttpApplication
{
public override string GetOutputCacheProviderName(HttpContext context)
{
if (AppSettingsHelper.GetSettingAsBool("UseCloud"))
{
return "CloudCache"; // name maps to one in web.config
}
else
{
return base.GetOutputCacheProviderName(context);
}
}
}

Summary

In this post, we've looked at the new OutputCacheProvider model added to ASP.NET 4.0. We've looked at the constraints under which new cache provider classes must live and how to integrate them into our sites once written, depending on whether we need caching to work at a control or a page level.

Until next time, happy coding!