State and Sessions in Suave
While web applications are technically stateless, there are still times where we need to start from a known state. So, let’s jump in and look at aspects of session cookies first, then how we can manage state among
Cookie State Session Storage
Suave provides storage interfaces for cookies in the
Suave.State.CookieStateStore module. The
statefulForSession WebPart can be composed to make a path session-aware. From there, the
HttpContext.state function extracts the state information, and the
set functions on the resulting
StateStore object can be used to manipulate the contents of the state tracked by the session.
The contents of the cookie are encrypted before the cookie is sent. Suave’s default configuration generates a new server key each time the server is restarted. While this is not wrong, users would likely get quite annoyed if they lost their state because the server was restarted. Additionally, specifying a server key lets load-balanced servers access the same information.
The key generated by Suave is secure; we just don’t need it changing. To get a key, you can use the following code, either in an .fsx file (be sure to reference
Suave.dll), or by placing the following code in your application’s entry point, before the
startWebServer. Run it once; it will write a file called
key.txt that contains a base-64 encoded string representing a random key, which we can use to configure our session key encryption. (If you put it in your application, be sure to remove it after you’ve run it.)
Now, key in hand, we can continue our example from above. (Note that hard-coding the key in the source code is a poor way to manage these keys; a configuration file is better, but environment variables or container configuration per environment is best.)
(of particular interest to .NET Core < netstandard2.0)
Suave uses the .NET Framework type
BinaryFormatter to serialize the
Map<string, obj> containing the session state; this is the default. However, the
BinaryFormatter was removed in the .NET Core API, and the
DataContractJsonSerializer does not recognize the
Map<string, obj> type. One option is to utilize JSON.NET to serialize this object. To use that, ensure you’ve added the
Newtonsoft.Json NuGet package to your project, then put the following code somewhere before the
suaveCfg definition in the example above.
Then, modify the configuration to use that serializer.
State among WebParts
Writers module, Suave provides the functions
unsetUserData for adding items to the context’s
userState property. The example below could be used to accrue a list of messages to be displayed to the user.
In this example,
View.page is a function that generates the output, using the user state
Map<string, obj> to display the messages in a nice way.
We’ve covered two different ways of managing state. Session state persists throughout the session, while
userData has a per-request lifetime.