2

I've seen this type of question asked several times, but I can't figure out a correct and clean way to do this. On the post action, my PossibleAnswers property isn't set anymore (normal, as I'm not posting it back). How should I set it again, as the data is coming from the DB? Querying the db again doesn't seem logical to me, although I guess it works. Is there an alternative solution, like caching the list?

Controller

public ActionResult EditFirstCharac()
{
        var userId = _userService.GetUserIdFromName(_userName);
        var charac = _characService.GetAllUserCharacteristics(userId).ToList().FirstOrDefault(p => p.SelectedAnswer != null);

        var vm = new EditCharacViewModel()
        {
            CharacId = charac.Id,
            IsKey = charac.IsKey,
            Question = charac.Question.Title,
            Weight = charac.Weight,
            PossibleAnswers = charac.Question.PossibleAnswers.ToListSelectListItem(p => p.Id.ToString(), p => p.Label).ToList()
        };

        return View("Edit", vm);
    }

    [HttpPost]
    public ActionResult EditFirstCharac(EditCharacViewModel vm)
    {
        if (ModelState.IsValid)
        {
            // OK, save to DB or whatever
        }
        // KO, PossibleAnswers is empty
        return View("Edit", vm);
    }

ViewModel

public class EditCharacViewModel
{
    public int CharacId { get; set; }
    public string Question { get; set; }

    [Range(0, 5)]
    public int Weight { get; set; }

    public bool IsKey { get; set; }
    public List<SelectListItem> PossibleAnswers { get; set; }
    public string SelectedAnswer { get; set; }
}

View @model Dating.WebSite.ViewModels.Profile.EditCharacViewModel

@using (Html.BeginForm("EditFirstCharac", "Profile"))
{
    <div>@Model.Question</div>

    @Html.EditorFor(p => p.IsKey)

    @Html.EditorFor(p => p.Weight)

    @Html.DropDownListFor(p => p.SelectedAnswer, Model.PossibleAnswers)

    @Html.HiddenFor(p => p.Question, new { id = "Question" })
    @Html.HiddenFor(p => p.CharacId, new { id = "CharacId" })
    <input type="submit" />
}
  • It seems you already have the answer. Going back and fetch the list again from DB is one way to go, although not very efficient. Is this PossibleAnswers a fixed list? I mean, does it values changes or not? If not, you can use a cache strategy like you said. – jpgrassi Dec 27 '15 at 14:33
  • @jpgrassi Yes it's a fixed list. Caching sounds good, but I have no idea how to do this. Thanks. – user3744187 Dec 27 '15 at 14:54
  • Well you could store it in the Application context, or use the .Net 4.0 MemoryCach (I have use this a couple of times and it works great). Take a look at these links:http://www.asp.net/web-forms/overview/data-access/caching-data/caching-data-at-application-startup-cs; http://stevescodingblog.co.uk/net4-caching-with-mvc/ – jpgrassi Dec 27 '15 at 15:15

1 Answers1

1

On the post action, my PossibleAnswers property isn't set anymore (normal, as I'm not posting it back).

This is the correct and expected behavior. Http is stateless. So your second request(POST) does not have any idea what you had for the PossibleAnswers property in your previous request(the GET request)

How should I set it again, as the data is coming from the DB? Querying the db again doesn't seem logical to me

Yes. You need to reload the data again. As i mentioned earlier, Http is stateless and your current(POST) request won't have the data you loaded in previous request. In ASP.NET Web forms, we used ViewState to persist data between requests. That was more like a hack. The content of the dropdown was encrypted to a string and stored in a hidden field and posted back to server. When posted back, server will decrypt the string and load the dropdown again. This hack/trick was typically against the concept of Http where one request should not have any idea of previous request.

So what you should be doing is

[HttpPost]
public ActionResult EditFirstCharac(EditCharacViewModel vm)
{
    if (ModelState.IsValid)
    {
        // OK, save to DB or whatever and Redirect to a GET action (PRG pattern)
    }
    //Reload data
    vm.PossibleAnswers = charac.Question.PossibleAnswers
                        .ToListSelectListItem(p => p.Id.ToString(), p => p.Label).ToList();
    return View("Edit", vm);
}
Shyju
  • 214,206
  • 104
  • 411
  • 497
  • thanks for your answer. Would you agree though that caching is also a good solution to not query the DB again ? (I know it has nothing to do with the answer you provided, just asking). Thanks again – user3744187 Dec 29 '15 at 09:19
  • Absolutely. Cache data like this which don't usually change). All lookup data is good candidates for caching. Here is an example http://stackoverflow.com/questions/33402051/asp-net-mvc-5-jsonresult-caching/33977384#33977384 and here is one for MVC6 http://stackoverflow.com/questions/34414310/httpruntime-cache-equivalent-for-asp-net-5-mvc-6/34418575#34418575 – Shyju Dec 29 '15 at 13:43
  • 1
    Thanks a lot for these very helpful links. – user3744187 Dec 29 '15 at 13:44