After having used NCommon in a couple of production projects, the one area that I have disliked is the Storage class. The problem with the static Storage factory has been that if a component relies on one of the Storage classes, it becomes a little bit of a pain to write unit tests for such components. Such unit tests would have to know way too much about which storage implementation the component uses and how it uses it. Session storage was a bigger pain, there’s no ideal way to replace a Session storage implementation that relies on an actual HttpSession while testing.
Eventually what I’d end up with is having wrappers around Storage that would be injected into components via the container. After having to write such plumbing code for the nth time, I figured it’s time for a change.
What’s in a name: Storage or State
The first round of refactoring was to get rid of the Storage naming pattern. While working on above said projects with other team members, I was asked countless number of times “So where does Storage store the data?” or “Do I need a database for Storage to work?”. And that would ensure the slow painful process of explaining that Storage is not “really” a persistent store, rather provides an way to maintain different states of an application. State is the keyword here, and instantly light bulbs would light and questions were answered.
Semantically, the name State is a better representation of what the original Storage class did in NCommon anyways. It provided a way to get access to an application’s state, or a sessions state or thread local state. So in 1.1 the root container of state is now called, wait for it… IState
19 /// <summary>
20 /// Base IState interface.
21 /// </summary>
22 public interface IState
23 {
24 /// <summary>
25 /// Gets the application specific state.
26 /// </summary>
27 IApplicationState Application { get; }
28 /// <summary>
29 /// Gets the session specific state.
30 /// </summary>
31 ISessionState Session { get; }
32 /// <summary>
33 /// Gets the cache specific state.
34 /// </summary>
35 ICacheState Cache { get; }
36 /// <summary>
37 /// Gets the thread local / request local specific state.
38 /// </summary>
39 ILocalState Local { get; }
40 }
IState pretty much exposes the same set of state implementations as the original Storage class; Application, Session, Local and one additional Cache. Now components can have implementations of IState injected via the container, and tests become cleaner because we can easily create subs/mocks of IState.
Each of the different state interfaces expose the same set of methods; Get, Put and Remove. ICacheState exposes additional overloads to Put to allow specifying expiration policies for cache entries.
The default implementation of IApplicationState and ICacheState are quite straightforward. DefaultApplicationState uses the current AppDomain, same as before, while the DefaultCacheState uses the Http runtime cache.
Session State, Local State, WCF and ASP.Net
Originally, NCommon Storage classes did not support WCF at all. Admittedly, I try to stay far away from WCF (topic for another time), so I had completely ignored the fact that there’d be users who would want to use NCommon in WCF services.
1.1 now provides native support for both WCF and ASP.Net. It goes one step further, if the current host is a WCF host and has AspNetCompatabilityRequirements behavior is applied on the current service, and if it the requirement is set to Allowed or Required, then it will automatically switch from using WCF OperationContext / InstanceContext to HttpContext and HttpSession (that is if the ASP.Net pipeline is present).
Configuring state in NCommon:
State in NCommon is pluggable, and that is intentional. I wanted to be able to replace state implementations based on project scenarios, one common one being replacing the default implementation of ICacheState that uses the http runtime cache to use memcached.
You can use the new configuration fluent interface in NCommon, introduced in this post, by using the ConfigureState method exposed by the static Configure class in NCommon. The ConfigureState method expects a type that implements IStateConfiguration which exposes one single method Configure. A default implementation of IStateConfiguration, DefaultStateConfiguration, is provided. This class exposes four methods that you can use to override the default state implementations that NCommon should use:
UseCustomCacheOf<T>()
UseCustomSessionStateOf<T>()
UseCustomLocalStateOf<T>()
UseCustomApplicationStateOf<T>()
Below is an example where the a custom Memcached cache state provider should be used by NCommon for cache state, rather than the default implemenation:
19 var container = new WindsorContainer();
20 var containerAdapter = new WindsorContainerAdapter(container);
21 NCommon.Configure.Using(containerAdapter)
22 .ConfigureState<DefaultStateConfiguration>(stateConfig =>
23 stateConfig.UseCustomApplicationStateOf<ICustomAppState>()
24 .UseCustomCacheOf<MemCachedState>());
25
Breaking changes:
In the 1.1 branch you won’t find the old Storage class anymore. This has been completely removed for now. So you might find that code that referenced Storage no longer compiles. I will add an implementation of Storage that used the new IState classes back, just for backwards compatibility, but I would strong suggest restructuring your components from using the static methods on Storage to have IState implementations injected via the container.