Home > Software engineering >  Access a complex data set in controller from a View's C# code block
Access a complex data set in controller from a View's C# code block

Time:12-15

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 >
            &copy; 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.

  • Related