2

I have a Product table which has many products in it. I have a Details Action Method in my HomeController which returns the product details in Details View Page.

Suppose: I have this data:

ProductID | ProductName | Price | CategoryId
    1     |  T-Shirt    |  120  |  Clothing
    2     |   Shirt     |  150  |  Clothing
    3     |   Watch     |  220  |  Watches
    4     |  Laptop     |  820  |  Computing
    5     | Samsung S6  |  520  |  Mobile
    6     |    Xbox     |  320  |  Gaming

Now, I want is that If some user visits T-Shirt then I want to add that T-shirt product in a new <div> of "Recently Viewed". If he again visits "Watch" then add watch product in "Recently Viewed" <div>.

Also I want to show more products based on his recently viewed products. I mean if he's visiting Xbox then Xbox will be added in recently viewed <div> and also more products related to "Gaming" category will be shown in a new <div> below the recently viewed <div>.

Here is what I'm trying, my idea is to just store the productId in the cookies and in the Details View Page, get Cookie Request, get the productId fro cookie and find the category of that product and show more products from that category.

HomeController

public ActionResult Details(int? id)
    {
        if (id == null)
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        Product product = db.Products.Find(id);
        if (product == null)
            return HttpNotFound();

        //Creating cookies
        HttpCookie _userActivity = new HttpCookie("UserActivity");
        _userActivity["ProductID"] = id.ToString();
        _userActivity["ProdutName"] = product.Name;
        _userActivity["Lastvisited"] = DateTime.Now.ToShortTimeString();

        //Adding Expire Time of cookies
        _userActivity.Expires = DateTime.Now.AddDays(5);

        //Adding cookies to current web response
        Response.Cookies.Add(_userActivity);

        //Reading cookies
        HttpCookie readcookie = Request.Cookies["UserActivity"];
        string productID , productName, lastVisited ;
        if (readcookie != null)
        {
            productID = readcookie["ProductID"];
            productName = readcookie["ProdutName"];
            lastVisited = readcookie["Lastvisited"];
        }

        return View(product);
    }

I wrote this in my Details View Page. It is showing me Recently View product's Id and details, but only 1 product's detail from cookies. not as my as i view

<div class="row">
        <div class="col-sm-9">
            @{
                var product = Request.Cookies["UserActivity"].Values;
            }
            <p>@product</p>

            <br />
            <h2>@Html.DisplayFor(model => model.Name)</h2>
 </div>
Mr Lister
  • 45,515
  • 15
  • 108
  • 150
user3395667
  • 43
  • 2
  • 8
  • Look at your cookie. You've structured it so that it only stores information for one ProductId. If you want to store information for multiple products, you're going to need to store some sort of collection instead of a single Id. – mason Dec 06 '15 at 19:08
  • @mason I didn't get your point sorry. Can you pls give an example of what you are trying to say. – user3395667 Dec 06 '15 at 19:10
  • Look at what you are storing in the cookie. You're storing a single ProductId. How do you expect it to show all the recently visited products if you've only structured it to store a single ID? – mason Dec 06 '15 at 19:12
  • Everytime you write a cookie with the same name, you overwrite the one that already exists (hence you only have last productid). That's what mason is trying to say (hope I'm right). You should store some List of productIds to cookie or better use some other mechanism to deliver list of recent productIds to View (maybe through ViewData). – Jure Dec 06 '15 at 19:25
  • @Jure Yeah you are right. I was doing it wrong. How can I do this with ViewData ? Can you write an example ? – user3395667 Dec 06 '15 at 19:35
  • @mason Thanks for the explanation, now I got your point. I'm trying to store it in the List. – user3395667 Dec 06 '15 at 19:36
  • @user3395667 Posted sample code as an answer. – Jure Dec 06 '15 at 20:04

1 Answers1

3

First you should make some class to hold your recent product information:

public class RecentProduct
{
    public int ProductId { get; set; }

    public string ProdutName { get; set; }

    public DateTime LastVisited { get; set; }
}

Maybe on load or somewhere on login event fill Session["RecentProductList"] with user's persisted recent list of products.

Then you have this function that stores recent product based on supplied information:

public void AddRecentProduct(List<RecentProduct> list, int id, string name, int maxItems)
{
    // list is current list of RecentProduct objects
    // Check if item already exists
    var item = list.FirstOrDefault(t => t.ProductId == id);
    // TODO: here if item is found, you could do some more coding
    //       to move item to the end of the list, since this is the
    //       last product referenced.
    if (item == null)
    {
        // Add item only if it does not exist
        list.Add(new RecentProduct
        {
            ProductId = id,
            ProdutName = name,
            LastVisited = DateTime.Now,
        });
    }

    // Check that recent product list does not exceed maxItems
    // (items at the top of the list are removed on FIFO basis;
    // first in, first out).
    while (list.Count > maxItems)
    {
        list.RemoveAt(0);
    }
}

Then you can minimize your controller's code for Details:

public ActionResult Details(int? id)
{
    if (id == null)
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    Product product = db.Products.Find(id);
    if (product == null)
        return HttpNotFound();

    // Read list of recent products from session
    var list = Session["RecentProductList"] as List<RecentProduct>;
    if (list == null)
    {
        // If list not found in session, create list and store it in a session
        list = new List<RecentProduct>();
        Session["RecentProductList"] = list;
    }

    // Add product to recent list (make list contain max 10 items; change if you like)
    AddRecentProduct(list, id.Value, product.Name, 10);

    // Store recentProductList to ViewData keyed as "RecentProductList" to use it in a view
    ViewData["RecentProductList"] = list;
    return View(product);
}

Then in your view read data from ViewData dictionary and display list of recent products:

<div class="row">
    <div class="col-sm-9">
        @{
            var recentProductList = ViewData["RecentProductList"] as List<RecentProduct>;
        }
        @* Do whatever you like with recentProductList here (e.g. display its data) *@
        @foreach (var recentProduct in recentProductList)
        {
            <p>@recentProduct.ProdutName (id: @recentProduct.ProductId)</p>
        }

        <br />
        <h2>@Html.DisplayFor(model => model.Name)</h2>
    </div>
</div>

Of course this code sample lacks some null checking and other stuff, but it should give you general idea on how to approach this functionality.

Jure
  • 1,156
  • 5
  • 15
  • I like the idea of storing recent products in database but I guess that might only work for registered users, How would I manage the guest visitors ? – user3395667 Dec 07 '15 at 08:14
  • For guest users you can also write user's info to database (limited, maybe just some name) so you get some user's identifier (ID). Then store this ID in a cookie and based on value from cookie, you get what this guest user has as a recent product list. User identifier can be GUID for example. – Jure Dec 07 '15 at 08:33
  • I am only getting the details of product that I am currently viewing. How can i store recentProductList in cookies or session ? I'm sorry but I couldn't do it. Can you just write the code line. – user3395667 Dec 07 '15 at 09:39
  • Where are you getting only details of product you're viewing? I've written foreach loop inside view code to show you how to display list of recent products. Inside @Html.DisplayFor you get properties displayed for current model that is current product. You do not store complete recentProductList to cookie. You only store reference to this recent list based on some user identifier. That is one way to go. I am sure there are many others. – Jure Dec 07 '15 at 10:04
  • I'm getting the product name & id of product that I'm currently viewing. If I goto `Product A` details page then it is showing `Product A (id: 1)` then when I goto another product's page lets say `Product B` then It is showing `Product B (id: 2)`, here it should display `Product A` because I recently view the `Product A` – user3395667 Dec 07 '15 at 11:00
  • You should persist recentProductList between requests, hence TODO in my posted code: `// TODO: Maybe save recentProductList to Session or even to database.` You'll have to load recentProductList every time from db or session, whichever you prefer. – Jure Dec 07 '15 at 12:32
  • Just for now lets just say I don't want to store and load from db. Lets put it in session. How would i do that ? I'm just a beginner – user3395667 Dec 07 '15 at 12:48
  • Thank you man! I guess now I have to make session timeout large because if a user visits at 12am and then at 9pm then it will not show recentproductList. or may be I could create cookie and store cookie in visitor's computer – user3395667 Dec 07 '15 at 15:15
  • You can create some new class that encapsulates List of RecentProduct, and assign it some unique ID (e.g. Guid.NewGuid()) and store that in a cookie. Then whenever some guest browses to your site, you select appropriate element from that object (based on a guid value from a cookie). In any case these objects should then be persisted to database, to survive session endings. In this case you do not need to increase session timeout. – Jure Dec 07 '15 at 20:30