Сохранение данных модели при публикации формы при повторном отображении представления недопустимого ModelState - PullRequest
1 голос
/ 26 сентября 2011

Упрощенный пример:

[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.IsValid)
    {
        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);
    }
}

У меня вопрос: правильно ли я поступаю, сохраняя данные отчета в TempData? Код кажется немного странным, особенно чтение и последующая запись в TempData в методе действия HttpPost, чтобы убедиться, что он сохраняет следующий запрос.

Другие возможные варианты:

(1) Сделайте еще один вызов на сервисном уровне из действия HttpPost (я бы не стал делать еще один вызов базы данных из-за сбоя проверки, просто чтобы снова отобразить форму, поскольку она кажется неэффективной). Я думаю, я мог бы реализовать кэширование на уровне сервиса, чтобы избежать обхода базы данных ...

(2) Используйте скрытые вводы в форме (юк!).

(3) Постоянно хранить последний просмотренный отчет в сеансе.

Как все остальные делают такие вещи? Какая рекомендуемая практика?

1 Ответ

3 голосов
/ 27 сентября 2011

У меня вопрос: правильно ли я поступаю, сохраняя данные отчета в TempData?

Нет, абсолютно нет. Сохраните что-нибудь в TempData тогда и только тогда, когда вы сразу после этого перенаправляете, так как TempData переживает только одно перенаправление. Если вы сохраните что-то в TempData в своем действии GET и затем отобразите представление, AJAX-запрос, например, из этого представления, уничтожит TempData, и вы не вернете значения обратно в свой запрос POST.

Правильный шаблон следующий (нет TempData вообще):

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) Сделайте еще один вызов на сервисном уровне из действия HttpPost (Я бы предпочел не делать еще один вызов базы данных из-за проверки невозможность просто перерисовать форму, так как она кажется неэффективной). Я предполагаю, что я может реализовать кэширование на уровне службы, чтобы избежать базы данных туда и обратно ...

Это именно то, что вы должны сделать. И если у вас есть проблемы с оптимизацией этих запросов или опасения поразить вас или что-то в каждом POST-запросе, кешируйте эти результаты. В настоящее время базы данных гипероптимизированы и предназначены именно для этого (не злоупотребляйте, конечно, определяйте индексы по соответствующим столбцам, и производительность должна быть хорошей). Но, конечно, кэширование - лучший способ избежать попадания в базу данных, если у вас очень требовательный веб-сайт с большим количеством запросов и пользователей.

(2) Используйте скрытые вводы в форме (юк!).

Юк, я согласен, но мог бы работать в ситуациях, когда их у вас не много.

(3) Постоянно хранить последний просмотренный отчет в сеансе.

Нет, избегайте сессии. Сессия - враг масштабируемых приложений без сохранения состояния.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...