0

I am setting up an ASP.NET MVC website and I am having a problem looping through a session variable in the client. The session variable is a List that I want to be a list of sites that will exist in a dropdown list in the navbar on all pages. So, this will exist within the _Layout.cshtml. At the moment I am setting the session variables with the HomeController.

I used this stackoverflow post to get as far as I have done so far. However this post did not deal with displaying the list in the client:

The backend code is below.

Session Class:

namespace Customer_Application.Models
{
    public class UserSiteList
    {
        public string? Site { get; set; }
        public string? User { get; set; }
    }
}

SesssionExtensions class:

using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Text.Json;

namespace Customer_Application.DataLayer
{
    public static class SessionExtensions
    {
        public static void Set<T>(this ISession session, string key, T value)
        {
            session.SetString(key, JsonSerializer.Serialize(value));
        }

        public static T Get<T>(this ISession session, string key)
        {
            var value = session.GetString(key);
            return value == null ? default : JsonSerializer.Deserialize<T>(value);
        }
    }
}

HomeController:

public IActionResult Index(int id)
{
    string sql = $"SELECT ID FROM [database].[dbo].[tblLogin] WHERE ID = {id}";
    string username = _SharedFunctions.String_Required(sql);

    contxt.HttpContext.Session.SetInt32("userID", id);
    contxt.HttpContext.Session.SetString("username", username);

    // Gets the site list for the user and adds to session
    userSiteList = new List<UserSiteList>
    {
        new UserSiteList { Site = "siteA", User = "dave.smith" },
        new UserSiteList { Site = "siteB", User = "dave.smith" }
    };
    contxt.HttpContext.Session.Set<List<UserSiteList>>("userSites", userSiteList);
    var value = HttpContext.Session.Get<List<UserSiteList>>("userSites");

    object Dashboard_inf = new Dashboard();

    return View(Dashboard_inf);
}

The value of 'value' is as expected:

enter image description here

And when returned using the code 'return Json(value)', the follow is returned to the client:

enter image description here

So I try to use this in the client:

_Layout.cshtml:

@inject IHttpContextAccessor contxt;

@{
    var userSites = contxt.HttpContext.Session.Get("userSites");
}
<!DOCTYPE html>
<html lang="en">
<head>
.
.
.
<ul class="navbar-nav flex-grow-1 pt-1">
    <li class="nav_item dropdown">
        <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
            Sites
        </a>
        <ul class="dropdown-menu">
             @foreach (var item in userSites)
             {
                 <li>@item</li>
             }
        </ul>
    </li>
.
.

However this just produces a list of ascii character codes within the drop down list.

enter image description here

I think that this is something to do with how the 'userSites' variable is assigned in the _Layout.cshtml. I am pretty sure that '.Get' is incorrect, but do not know how to assign this otherwise.

Any help would be appreciated.

Chris
  • 13
  • 4
  • In one code you tell Get what type of object to get, in the other you don’t so it’ll return a string most probably – Sami Kuhmonen Feb 16 '23 at 15:40
  • "@item.Site" instead of "@item." I wouldn't set it in the HomeController since it's on the shared layout. Render a child and handle populating it inside the child controller so you only have to do it once. – GH DevOps Feb 16 '23 at 15:49
  • Thankyou for your responses. @SamiKuhmonen: not sure what you mean but as you can see from the screen grab that it is a collection that can be enumerated, so I am pretty sure it is not just a string. – Chris Feb 16 '23 at 16:08
  • @GH DevOps: In regards to "@item.Site", I have tried that and 'Site' is highlighted as an error with the comment: "CS1061: 'byte' does not contain a definition for 'Site' and no accessible extension method 'Site' accepting a first argument of type 'byte' could be found (are you missing a directive or an assembly reference?)". This is why I believe I have declared the variable incorrectly at the top of _Layout.cshtml. – Chris Feb 16 '23 at 16:12
  • You're returning Dashboard_inf instead of userSiteList. Bind your view with userSiteList and "@item.Site" will be available. – GH DevOps Feb 16 '23 at 16:19
  • As far as I can tell you cannot mass multiple models to the view in ASP.NET. and I need dashboard to be passed to the view. I want the session variable available on all pages, hence why I am setting it up within this method. whether I should do this elsewhere, is not the issue, I am just trying to get it to work. As you can see in the HomeController code above, I have set session variables of 'userID' and 'username' which I have successfully displayed in the navbar on all pages following then being set up here. I want to do the same with the site list as a session variable. – Chris Feb 16 '23 at 16:32

1 Answers1

0

if you want to pass two piece of data you will have to create a ViewMOdel

public class ViewModel
{
   public List<UserSiteList>> userSiteList {get; set;}
   public Dashboard dashboard {get;set;}
}

now you have to fix your controller code

// comment this code. What is this for?

  //contxt.HttpContext.Session.Set<List<UserSiteList>>("userSites", userSiteList);
//var value = HttpContext.Session.Get<List<UserSiteList>>("userSites");
//
 var model = new ViewModel{
         dashboard = new Dashboard();
         userSiteList= userSiteList
}



    return View(model);

and fix a view model, replace

@{
    var userSites = contxt.HttpContext.Session.Get("userSites");
}

with

@model ViewModel

and fix this code,should be

             @foreach (var item in Model.userSiteList )
             {
                 <li>@item.Site</li>
                   <li>@item.User</li>
             }
Serge
  • 40,935
  • 4
  • 18
  • 45
  • Thanks for responding. However if I do that, I loose the Dashboard. I need the Dashboard. – Chris Feb 16 '23 at 16:40
  • @Chris What is a Dashboard? I can't see any use – Serge Feb 16 '23 at 16:40
  • So the _Layout.cshtml is the master page the deals with the header and footer etc, basically the stuff I want on every page. I then have a home index.cshtml view that displays the dashboard. The dashboard is the landing page that displays data the customer is interested in. A Dashboard object is instantiated from the Dashboard Class and passed to the client to display using @Model. So you see I need that and I cannot pass another model. I want the site drop down list to display in the navbar on every page, so I am setting it up as a session variable which can be accessed by all pages – Chris Feb 16 '23 at 16:47
  • Thanks for that. However that would only make it available within that view. I would have to do the same on every controller. So really I would like it to be a session variable. – Chris Feb 16 '23 at 17:02
  • btw thanks for showing me how I pass multiple models - I will use that elsewhere, but I do not want to use it to solve this issue. – Chris Feb 16 '23 at 17:04
  • @Chris You have to google how to create Components. This is what is used for this case. – Serge Feb 16 '23 at 17:11