Remember me, (re)store visited pages and categories

I’m looking forward to the Profile Store in EPiServer, but in the mean time I want some information to be remembered.
You can, of course, create your own persistent visitor groups, but who knows what will change when the Profile Store arrives.

I just wanted the Visited Pages to be remembered, and perhaps the Visited Categories. These are stored in your session, so until it is clear what will change when the Profile Store arrives,  I opted for "hack".

In the base class for my page controllers i added the following:

public virtual void UpdateViewedPagesCookie()
        {
            HttpSessionStateBase httpSessionStateBase = null;

            try
            {
                httpSessionStateBase = this.ControllerContext.HttpContext.Session;
            }
            catch (NotImplementedException)
            {
            }

            if (httpSessionStateBase == null)
            {
                return;
            }

            HashSet<PageReference> viewedPages = null;
            try
            {
                viewedPages = httpSessionStateBase["EPi:ViewedPages"] as HashSet<PageReference>;
            }
            catch (NotImplementedException)
            {
            }

            if (viewedPages == null)
            {
                return;
            }

            string content = JsonConvert.SerializeObject(viewedPages);

            HttpCookie myCookie = this.Request.Cookies["EPi: ViewedPages"];

            if (myCookie == null)
            {
                try
                {
                    myCookie = new HttpCookie("EPi: ViewedPages") { Value = content, Expires = DateTime.Now.AddYears(1) };
                    this.Response.Cookies.Add(myCookie);
                }
                catch (ArgumentOutOfRangeException)
                {
                }
                catch (NotImplementedException)
                {
                }

                return;
            }

            try
            {
                myCookie.Value = content;
                myCookie.Expires = DateTime.Now.AddYears(1);
                this.Response.Cookies.Set(myCookie);
            }
            catch (ArgumentOutOfRangeException)
            {
            }
            catch (NotImplementedException)
            {
            }
        }
		
		
		public void UpdateVisitedCategoriesCookie()
        {
            HttpSessionStateBase httpSessionStateBase = null;

            try
            {
                httpSessionStateBase = this.ControllerContext.HttpContext.Session;
            }
            catch (NotImplementedException)
            {
            }

            if (httpSessionStateBase == null)
            {
                return;
            }

            HashSet<PageReference> viewdcategories = null;
            
            try
            {
                foreach (string key in httpSessionStateBase.Keys.Cast<string>().Where(key => key.Contains("EPi:VisitedCategories")))
                {
                    HttpCookie myCookie = this.Request.Cookies[key];
                    string content = string.Empty;

                    try
                    {
                        viewdcategories = httpSessionStateBase[key] as HashSet<PageReference>;
                    }
                    catch (NotImplementedException)
                    {
                    }

                    content = viewdcategories != null ? JsonConvert.SerializeObject(viewdcategories) : JsonConvert.SerializeObject(true);
                    

                    if (myCookie == null)
                    {
                        try
                        {
                            myCookie = new HttpCookie(key) { Value = content, Expires = DateTime.Now.AddYears(1) };
                            this.Response.Cookies.Add(myCookie);
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                        }
                        catch (NotImplementedException)
                        {
                        }
                    }
                    else
                    {
                        try
                        {
                            myCookie.Value = content;
                            myCookie.Expires = DateTime.Now.AddYears(1);
                            this.Response.Cookies.Set(myCookie);
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                        }
                        catch (NotImplementedException)
                        {
                        }
                    }
                }
            }
            catch (NotImplementedException)
            {
            }
            catch (ArgumentNullException)
            {
            }
            catch (InvalidCastException)
            {
            }
        }

All I do is create/update cookies for the session variables that the Visited Pages and Visited Categories use.

In the Session_Start of the global. asax you can set the session again with information from those cookies:

public class EPiServerApplication : EPiServer.Global
    {
        protected void Session_Start(object sender, EventArgs e)
        {
             this.UpdateViewedPagesSession();
            this.UpdateViewedCategoriesSession();
        }
		
		 protected void UpdateViewedPagesSession()
        {
            HttpCookie myCookie = null;

            try
            {
                myCookie = this.Request.Cookies["EPi: ViewedPages"];
            }
            catch (HttpException)
            {
            }

            if (myCookie == null)
            {
                return;
            }

            HashSet<PageReference> viewedPages = JsonConvert.DeserializeObject<HashSet<PageReference>>(myCookie.Value);
            HttpContext.Current.Session["EPi:ViewedPages"] = viewedPages;
        }
		
		protected void UpdateViewedCategoriesSession()
        {
            try
            {
                foreach (string key in
                    this.Request.Cookies.Keys.Cast<string>().Where(key => key.Contains("EPi:VisitedCategories")))
                {
                    HttpCookie myCookie = null;

                    try
                    {
                        myCookie = this.Request.Cookies[key];
                    }
                    catch (HttpException)
                    {
                    }

                    if (myCookie == null)
                    {
                        return;
                    }

                    if (myCookie.Value.Equals("true", StringComparison.OrdinalIgnoreCase))
                    {
                        HttpContext.Current.Session[key] = JsonConvert.DeserializeObject<bool>("true");
                    }
                    else
                    {
                        HashSet<PageReference> viewedCategories = JsonConvert.DeserializeObject<HashSet<PageReference>>(myCookie.Value);
                        HttpContext.Current.Session[key] = viewedCategories;
                    }
                }
            }
            catch (HttpException)
            {
            }
            catch (ArgumentNullException)
            {
            }
            catch (InvalidCastException)
            { 
            }
            catch (ArgumentException)
            {
            }
    }

As I said, until I know more about what will happen with the Profile Store, I opt for this way, although a bit hackish… It can be easily removed and does not introduce new stuff that might need to be completely rewritten and/or migrated when the Profile Store arrives.

You can also find the code in a gist.

4 thoughts on “Remember me, (re)store visited pages and categories

Leave a comment