I set a complex data of a particular Model type. Now I want to access that in a View's code block.
I tried using HttpContext.Session.GetComplexData<List>("productsInCart"); in code block, and also Context.Session.GetString("productsInCart").
I don't want to use ViewBag or it's related solution, because my controller action which sets complex data doesn't return a View.
Controller Method
public IActionResult GetProductByIdToAddInCart(GetProductInputModel model)
{
var productById = _GetProductAPICall.GetProductsById(model);
var products = HttpContext.Session.GetComplexData<List<GetProductOutputModel>>("productsInCart");
if(products != null && products.Count() != 0)
{
products.Add(productById);
HttpContext.Session.SetComplexData("productsInCart", products.Distinct());
}
else
{
var firstProductInCart = new List<GetProductOutputModel>();
firstProductInCart.Add(productById);
HttpContext.Session.SetComplexData("productsInCart", firstProductInCart);
}
var productsInCart = HttpContext.Session.GetComplexData<List<GetProductOutputModel>>("productsInCart");
return Ok(new { data = productsInCart });
}
CodePudding user response:
Here is a working demo about how to use the complex data in session and display it in _Layout.cshtml:
Extension
namespace MvcProj.Services
{
public static class SessionExtensions
{
public static void SetComplexData<T>(this ISession session, string key, T value)
{
session.SetString(key, System.Text.Json.JsonSerializer.Serialize(value));
}
public static T? GetComplexData<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default : System.Text.Json.JsonSerializer.Deserialize<T>(value);
}
}
}
Get the session in _Layout.cshtml
@using MvcProj.Models; @*model namespace*@
@using MvcProj.Services; @*extension namespace*@
@{
var data = Context.Session.GetComplexData<List<GetProductOutputModel>>("productsInCart");
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - MvcProj</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/MvcProj.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav >
<div >
<a asp-area="" asp-controller="Home" asp-action="Index">MvcProj</a>
<button type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span ></span>
</button>
<div >
<ul >
<li >
<a asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li >
<a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div >
<main role="main" >
@if(data!=null)
{
<table>
@foreach(var item in data)
{
<tr>
<td>@item.Name</td>
</tr>
}
</table>
}
@RenderBody()
</main>
</div>
<footer >
<div >
© 2022 - MvcProj - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<script src="~/js/myBundle.js"></script>
@await RenderSectionAsync("Scripts", required: false)
</body>
</html>
Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedMemoryCache(); //add this..
builder.Services.AddSession(); //add this..
var app = builder. Build();
app.UseHttpsRedirection();
app.UseWebOptimizer();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession(); //add this..
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
When you call the GetProductByIdToAddInCart
method then it will display the data in each view which apply the _Layout.cshtml as Layout.
CodePudding user response:
You have a couple of options, as I see it.
It sounds as if, when you return the View
, you already have the complex data in Session
. If that's the case, you can simply put it in ViewBag
from within the action that returns the View.
Or, you can use a more complex model, like so:
var model = new Tuple<MyModel, List<Product>>(
myModel,
HttpContext.Session.GetComplexData<List<Product>>("productsInCart")
);
Return MyView(model);
(I am assuming a model called MyModel
and that the complex data is a List<Product>
.)
If you do that, you will have to change the definition of the @model
from within the View, to reflect that it's a different type now.
You would refer to the new model from within the View like this:
%for(var record in model.Item2) {
<div><%= record.ProductId %></div>
... etc.
Alternatively, you could use some Ajax code to make a call to the controller that returns the complex data, but that's usually something that's triggered by an action from the user, which you haven't mentioned.