Simplified example:
[HttpGet]
public ActionResult Report(DateTime? date)
{
if (!date.HasValue)
{
date = DateTime.Now;
}
// Clear the ModelState so that the date is displayed in the correct format as specified by the DisplayFormat attribute on the model
ModelState.Clear();
// Expensive call to database to retrieve the report data
ReportModel model = DataAdapter.Convert(this.reportService.GetReport((DateTime)date));
// Store in TempData in case validation fails on HttpPost
TempData["ReportModel"] = model;
return View(model);
}
[HttpPost]
public ActionResult Report(ReportModel model)
{
if (ModelState.Is开发者_如何学编程Valid)
{
return RedirectToAction("Report", new { date = model.Date });
}
else
{
// Load the report from TempData, and restore again in case of another validation failure
model = TempData["ReportModel"] as ReportModel;
TempData["ReportModel"] = model;
// Redisplay the view, the user inputted value for date will be loaded from ModelState
return View(model);
}
}
My question is, am I going about this the right way by storing the report data in TempData? The code seems a little strange especially reading from and then writing back to TempData in the HttpPost action method to ensure it persists the next request.
Other options I can think of are:
(1) Make another call to the service layer from the HttpPost action (I'd rather not make another database call because of a validation failure just to redisplay the form as it seems inefficient). I guess I could implement caching at the service layer to avoid the database round trip...
(2) Use hidden inputs in the form (yuk!).
(3) Store the most recently viewed report in session permanently.
How is everyone else doing this sort of thing? What's the recommended practice?
My question is, am I going about this the right way by storing the report data in TempData?
No, absolutely not. Store something into TempData if and only if you redirect immediately afterwards as TempData survivces only a single redirect. If you store something into TempData in your GET action and then render a view, an AJAX request for example from this view would kill the TempData and you won't get the values back on your POST request.
The correct pattern is the following (no TempData
whatsoever):
public ActionResult Report(DateTime? date)
{
if (!date.HasValue)
{
date = DateTime.Now;
}
// Clear the ModelState so that the date is displayed in the correct format as specified by the DisplayFormat attribute on the model
ModelState.Clear();
// Expensive call to database to retrieve the report data
ReportModel model = DataAdapter.Convert(this.reportService.GetReport((DateTime)date));
return View(model);
}
[HttpPost]
public ActionResult Report(ReportModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Report", new { date = model.Date });
}
else
{
// Redisplay the view, the user inputted value for date will be loaded from ModelState
// TODO: query the database/cache to refetch any fields that weren't present
// in the form and that you need when redisplaying the view
return View(model);
}
}
(1) Make another call to the service layer from the HttpPost action (I'd rather not make another database call because of a validation failure just to redisplay the form as it seems inefficient). I guess I could implement caching at the service layer to avoid the database round trip...
That's exactly what you should do. And if you have problems with optimizing those queries or concerns of hitting your or something on each POST request cache those results. Databases are hyper optimized nowadays and are designed to do exactly this (don't abuse of course, define your indexes on proper columns and performance should be good). But of course caching is the best way to avoid hitting the database if you have a very demanding web site with lots of requests and users.
(2) Use hidden inputs in the form (yuk!).
Yuk, I agree but could work in situations where you don't have lots of them.
(3) Store the most recently viewed report in session permanently.
No, avoid Session. Session is the enemy of scalable and stateless applications.
精彩评论