Darf Zon
Darf Zon

Reputation: 6378

How to persist the data in memory in MVC controller?

Please look at the below action. When the user navigate the first time, creates a object, then while he navigates in the page, access again to the Action but through Ajax request and the data disappers (worksheets = null).

    private static List<Worksheet> worksheets;
    public ActionResult DoTest()
    {
        if (Request.IsAjaxRequest())
        {
            return PartialView("_Problems", worksheets[1]);
        }

        // first time
        worksheets = new List<Worksheet>()
        {
            new Worksheet("Hoja 1", ...),
            new Worksheet("Hoja 2", ...)
        };
        return View(worksheets[0]);
    }

My first solution was set the variable worksheets to static, but I supposed this is not a good practice. Am I doing a good way or are there another tweeks?

Upvotes: 7

Views: 14418

Answers (3)

Mohamad Elnaqeeb
Mohamad Elnaqeeb

Reputation: 563

In ASP.NET Core Session doesn't support Generic data type you'll need to add this extension

using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

public static class SessionExtensions
{
    public static void Set<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonConvert.SerializeObject(value));
    }

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

and to use it:

public IActionResult SetDate()
{
    // Requires you add the Set extension method mentioned in the article.
    HttpContext.Session.Set<DateTime>(SessionKeyDate, DateTime.Now);
    return RedirectToAction("GetDate");
}

public IActionResult GetDate()
{
    // Requires you add the Get extension method mentioned in the article.
    var date = HttpContext.Session.Get<DateTime>(SessionKeyDate);
    var sessionTime = date.TimeOfDay.ToString();
    var currentTime = DateTime.Now.TimeOfDay.ToString();

    return Content($"Current time: {currentTime} - "
                 + $"session time: {sessionTime}");
}

Upvotes: 0

Brian Parks
Brian Parks

Reputation: 197

The instance of your controller does not persist across requests (This is why making worksheets static works, but keeping it non-static does not -- the object is only populated on a non-AJAX request due to your if statement).

One option is to populate the object no matter how the request comes in and then use the if statement to decide which item to return. The other (probably better) solution is to use the session, as Ulises mentioned.

Upvotes: 1

Ulises
Ulises

Reputation: 13429

Stay away from static variables, especially if the data is user-dependent. You could take advantage of the ASP.NET Session object.

This can be easily done in your case by changing your worksheets field to a property that stores its value in the Session object. This way, it will be available on subsequent calls. Example:

  private List<Worksheet> worksheets
  {
    get{ return Session["worksheets"] as List<Worksheet>;}
    set{ Session["worksheets"] = value; }
  }

  public ActionResult DoTest()
  {
      if (Request.IsAjaxRequest())
      {
        return PartialView("_Problems", worksheets[1]);
      }

      // first time
      worksheets = new List<Worksheet>()
      {
          new Worksheet("Hoja 1", ...),
          new Worksheet("Hoja 2", ...)
      };
      return View(worksheets[0]);
  }

Upvotes: 11

Related Questions