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 WebPart
s.
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 get
and set
functions on the resulting StateStore
object can be used to manipulate the contents of the state tracked by the session.
Server Keys
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.)
Cookie Serialization
(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
Within the Writers
module, Suave provides the functions setUserData
and 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.