0

I have a page which lets me create and save a record. When I click Save, I want to stay on the same page, but have that page display an updated view model. The problem I'm having is that after I save, the GET parameters stay in the page URL.

When I run my application, I go to the "list records" page and click the "create new" button. That causes a GET request to EditRecord with the createNew parameter set to true. The request looks like localhost/Home/EditRecord?createNew=True

public ActionResult EditRecord(string id, bool createNew = false)
{
    MyRecordViewModel viewModel;
    if (createNew)
    {
        viewModel = new MyRecordViewModel
        {
            IsNew = true
        };
    }
    else
    { 
        var myRecord = (from p in this.context.MyRecords
                        where p.Id = id
                        select p).FirstOrDefault();
        if (myRecord == null)
        {
            this.ErrorMessage("Cannot find record.");
            return View();
        }
        viewModel = new MyRecordViewModel(myRecord);
    }

    return View(viewModel);
}

Then when I click save, it POSTs to this method

[HttpPost]
public ActionResult EditRecord(MyRecordViewModel viewModel)
{
    // Save record to database
    // ...

    // Update the view model
    viewModel.LastUpdatedDttm = DateTime.Now;

    // Clear the model state dictionary so that my updated view model's values will be shown on the page
    ModelState.Clear();

    // Go back to the same page with an updated view model
    return View(viewModel);
}

The updated page is displayed correctly with the updated view model. The problem is that the URL is still localhost/Home/EditRecord?createNew=True. I want the URL to be localhost/Home/EditRecord

I don't want to redirect back to the GET page with my record ID and with createNew equal to false, because that'll cause an unnecessary trip to the database in order to redisplay the same record.

7
  • I suggest you follow the PRG pattern where you redirect to the GET action after successful save. What issue are you having when you do PRG pattern. Commented Jul 5, 2017 at 15:17
  • Doesn't the GET part involve a trip to database to select data that I already have available? I'm trying avoid unnecessary database access. Commented Jul 5, 2017 at 15:26
  • It does. It might be a clean approach to read it fresh from the db in the GET. Why would you worry about a single database hit ? Commented Jul 5, 2017 at 15:30
  • For a simple little page like this one it's not a problem, but some of my pages display a large amount of data from several tables, and the database trip could be noticeable. It's not a huge deal, but I'm trying to make this application as efficient as possible. Commented Jul 5, 2017 at 15:34
  • What is happening after you save, reload the page by clicking browser refresh button. Commented Jul 5, 2017 at 15:36

2 Answers 2

1

You need to use the PRG (Post-Redirect-Get) pattern. Simply, after you successfully do your edit or whatever, do not return the view again, but instead return a redirect. If you want the same page loaded again, just redirect to the same page. The key is that by doing the redirect, you're reloading everything fresh without carry over in things like the URL. This also then negates the need to do antipatterns like ModelState.Clear().

Sign up to request clarification or add additional context in comments.

2 Comments

I was trying to avoid that since the GET involves another trip to my database to select data that I already have available within my POST. Am I implementing PRG incorrectly?
And? In your attempt at micro-optimization, you broke a bunch of functionality that just works otherwise. If you have to reissue the query, do that. It's really not that big a deal. If the query takes too long either optimize the query or throw more resources at your database. Alternatively, you can employ memory caching to avoid the round trip.
0
public ActionResult EditRecord(string id, bool createNew = false)
{
    id = id ?? TempData["id"];

    //your code
}


[HttpPost]
public ActionResult EditProductAlias(MyRecordViewModel viewModel)
{
    //your code

    TempData[id] = viewModel.Id;

    return RedirectToAction("EditRecord", "ControllerName")
}

But it very bad solution

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.