views:

410

answers:

3

Hi,

So, I have a series of product pages and all I'd like to do is store the last 5 products viewed in a cookie so it can be displayed as a site-history. The problem I have isn't adding the five initial items to the cookie, its when they view 6, 7 or 10 items. Does anyone have any really decent suggestions on how to tackle this?

Currently I have this flawed logic (i have replaced the cookie name (xxx) for brevity);

Dim i As Integer = 0
        Dim productcount As Integer = 0

        If HttpContext.Current.Request.Cookies("xxx") Is Nothing Then
            Dim gingernuts As New HttpCookie("xxx")
            gingernuts.Values("productcount") = 0
            gingernuts.Expires = DateTime.Now.AddDays(365)
            HttpContext.Current.Response.Cookies.Add(gingernuts)
        End If

        productcount = HttpContext.Current.Request.Cookies("xxx")("productcount")

        For i = 0 To productcount
            If HttpContext.Current.Request.Cookies("xxx")("product" & i & "") = "" Then
                HttpContext.Current.Response.Cookies("xxx")("product" & i & "") = Request.QueryString("id")
            Else
                HttpContext.Current.Response.Cookies("xxx")("product" & i & "") = HttpContext.Current.Request.Cookies("xxx")("product" & i & "")
            End If
        Next

        If productcount = 5 Then
            HttpContext.Current.Response.Cookies("xxx")("productcount") = 5
            HttpContext.Current.Response.Cookies("xxx")("product0") = ""
        Else
            HttpContext.Current.Response.Cookies("xxx")("productcount") = productcount + 1
        End If

Suggestions and critisism welcomed and appreciated.

Chris

+1  A: 

This is how i will do it, if I am understanding your question right :)
If product count is less than 5 just append the new product. Else replace product0 with product1 till 4 and then add new product at 4

    If productcount < 5 Then 'Do the null value check before this
        HttpContext.Current.Response.Cookies("xxx")("productcount") = productCount + 1
        HttpContext.Current.Response.Cookies("xxx")("product" & productCount + 1) = ""

    Else
        For i = 0 To productcount - 1
           'Replace product 0 with 1, 1 with 2...till 3 with 4 
            HttpContext.Current.Response.Cookies("xxx")("product" & i & "") = HttpContext.Current.Response.Cookies("xxx")("product" & i + 1& "")

       Next
       HttpContext.Current.Response.Cookies("xxx")("product" & 4 & "") =  Request.QueryString("id")
    End If
Ratnesh Maurya
+3  A: 

Just use a simple cookie value which is a comma delimited list of the most recently viewed product IDs. (Note my VB.NET is that strong).

MostRecentIDs as String() '' // Instance level variables
Const ListSize = 5

'' // in a method somewhere
context As HttpContext = HttpContext.Current
cookie As HttpCookie = context.Request.Cookies("mri")
mri As Queue(Of String)

If cookie Is Nothing Then
    mri = New Queue(Of String)(cookie.Value.Split(",".ToCharArray())
Else
    mri = New Queue(Of String)
    cookie = New HttpCookie("mri")
End If

If mri.Contains(Request.QueryString("id")) Then

    If mri.Count >= ListSize Then mri.Dequeue()

    mri.Enqueue(Request.QueryString("id"))

End If

MostRecentIDs = mri.ToArray();

cookie.Value = String.Join(",", MostRecentIDs)
cookie.Expires = DateTime.Now.AddDays(365)

context.Response.Add(cookie)
  • Now you have access to the most recent product IDs as a simple string array.
  • This code handles the case where the cookie has not yet been created.
  • The cookie itself is much smaller.
  • Managing the size of the list can easily be paramaterised.

Code above based on the tested C# code below that I dropped into an empty ASPX file:-

const int listSize = 8;
string[] _mru;

protected void Page_Load(object sender, EventArgs e)
{
 HttpCookie cookie = Request.Cookies["mru"];
 Queue<string> mru;
 if (cookie != null)
 {
  mru = new Queue<string>(cookie.Value.Split(','));
 }
 else
 {
  mru = new Queue<string>();
  cookie = new HttpCookie("mru"); 
 }

 if (!mru.Contains(Request.QueryString["id"]))
 {
  if (mru.Count >= listSize) mru.Dequeue();

  mru.Enqueue(Request.QueryString["id"]);
 }

 _mru = mru.ToArray();

 cookie.Value = String.Join(",", _mru);
 cookie.Expires = DateTime.Now.AddDays(365);

 Response.Cookies.Add(cookie);

}
AnthonyWJones
Hi Anthony, I'm new to learning about choosing the proper data structures for a problem. Can you explain why you chose the queue instead of a stack? When I originally read his problem I thought stack would fit best since he wants to show the last 5 items a user visited and a stack is LIFO.
Jon
@Jon, for a Most Recently Used list you need a FIFO structure. Consider, if when the capacity is reached you were to pop the last item off the stack before inserting the current one. This would result in the first items in the stack remaining there and only the top one changing once capacity is reached. What is needed is for the oldest item in the list to be removed first that is the bottom item not the top. Removing the bottom item first is the action of a FIFO (a queue) not a LIFO (a stack).
AnthonyWJones
Thanks so much for the explanation! That was a big help, makes perfect sense now.
Jon
This is a better solution than that of mine.. I just corrected your implementation
Ratnesh Maurya
OOPS!! by "your implementation" I meant the one in question..
Ratnesh Maurya
@Anthony, Many thanks - this is stunning and works wonderfully. I never knew about the collections class - but there is all sorts in here that help some of the most unusual problems. I'll post the VB for reference.... :)
Chris Laythorpe
Just out of complete curiousity, how could you ensure that what went into the queue (and then into the cookie) was unique? The last five products that were unique? I assume we'd have to read the array first for the value prior to entering it?
Chris Laythorpe
@Chris: use the Queue Contains method. I'll adjust the code since that seems to be a reasonable requirement.
AnthonyWJones
@Anthony; many thanks. It was more out of curiousity to be honest. Your code did exactly what I wished it too and I must thank you again for it. I hope others also find it as useful as I did.
Chris Laythorpe
A: 

Anthony answered this question perfectly, but for future reference and for those using VB, this is the code:

    Imports System.Collections.Generic

    Const listSize As Integer = 5
    Private _mru As String()

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim cookie As HttpCookie = Request.Cookies("mru")

        Dim mru As Queue(Of String)
        If cookie IsNot Nothing Then
            mru = New Queue(Of String)(cookie.Value.Split(","c))
        Else
            mru = New Queue(Of String)()
            cookie = New HttpCookie("mru")
        End If

        If mru.Count >= listSize Then
            mru.Dequeue()
        End If

        mru.Enqueue(Request.QueryString("id"))

        _mru = mru.ToArray()

        cookie.Value = [String].Join(",", _mru)
        cookie.Expires = DateTime.Now.AddDays(365)


        Response.Cookies.Add(cookie)
End Sub

Many thanks to all the contributors here also.

Chris Laythorpe