I had a case where a site demanded more from the anonymous identification module than it supported. Episerver Commerce relies heavily on that, so to support it, I decided to try replacing the module with a new OWIN middleware.
An "anonymous cart"
By default, Episerver uses the ASP.Net module, Anonymous Identification, to correlate and recognize HTTP requests from anonymous visitors (visitors who are not authenticated). It works by sending a cookie with a random key to the browser, upon first request.
For Episerver Commerce sites, being able to recognize the same visitor across requests is a vital feature, because it allows anonymous visitors to have a cart without being logged in.
I call this an "anonymous cart", because it is stored in the Episerver database like a regular cart. But the owner field is set to the anonymous ID from the cookie. And if there was no anonymous ID across requests, Episerver Commerce would create a new empty cart on every single request to the cart, which is definitely not intended behaviour.
But generally, this logic works fine out-of-the-box, in the following way:
- On each request, the module decrypts the cookie and stores the ID in the HttpRequest object. In case there is no such cookie, one is generated and sent.
- When our site attempts to load a cart, the anonymous ID is used in place of the customer ID. If no cart exists, the site can request to create one with the anonymous ID as customer ID.
- If the visitor logs in to a profile, a module in Episerver Commerce will automatically merge all carts belonging to the anonymous ID into the logged-in customer’s carts.
- If the visitor logs out, it starts over by generating a new anonymous ID and anonymous cart.
Native apps are cookieless
The above-mentioned logic works perfectly fine for websites. But native apps generally do not work with cookies.
So, if we do not make amendments to support that, apps will always work with a new cart on every request.
The simplest solution is to let the native app send a GUID value in a custom request header. And stop sending it when the visitor is authenticated.
An integration OWIN solution
To support both approaches (cookie and header), I created two OWIN middlewares to replace the AnonymousIdentificationModule (from ASP.Net) and the ProfileModule (from Episerver Commerce).
Besides, it also adds support for the new SameSite cookie property, which the old module does not support.
I chose to build OWIN middlewares, instead of HTTP modules, since OWIN is the modern way of building pipelines going forward. Besides, OWIN middlewares are much easier to build and integrate, than modules that contains event handlers.
My new Anonymous Identification Middleware works like this:
- On each request, the middleware looks for a custom header value. If no custom header value is found, it looks for a cookie value.
- If a header is found, the value is added to the OWIN context.
- If the user is authenticated, the middleware adds a response header with the same name, to signal that the app should stop sending this value.
- If a cookie is found, the value is added to the OWIN context.
- If the user is authenticated, the middleware tells the browser to delete the cookie.
- If the user is not authenticated, the middleware may, in some cases, extend the cookie lifetime.
- If a cookie is not found, a GUID value is generated and added to a new cookie.
Next is my new Profile Migration Middleware, which works like this:
- If the incoming request has an anonymous ID and is also authenticated, all carts, wish-lists and orders that are owned by that anonymous ID are merged into the logged-in user’s records.
- Provided that the web browser deletes the cookie, or the native app stops sending the custom request header, this middleware will only attempt profile migration once per authentication.
The source code and documentation for my solution are available in this GitHub repository.