ASP.Net MVC и state - как сохранить состояние между запросами

как довольно опытный ASP.Net разработчик только недавно начал использовать MVC, я немного борюсь, чтобы изменить свое мышление от традиционного способа "управления сервером и обработчиком событий", в более динамичный способ MVC. Я думаю, что я медленно добираюсь туда, но иногда "магия" MVC выбрасывает меня.

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

последняя часть не так важна, прямо сейчас я борюсь с чем-то таким тривиальным, как создание списка файлов и сохранение этого списка между запросами. В традиционном подходе это было бы чрезвычайно просто - данные сохранялись бы в ViewState. Но в MVC мне нужно передать данные между контроллером и видом, и я не полностью понимаю, как это должно работать.

думаю, мне лучше опубликовать мою довольно незавершенную попытку кодирования этого, чтобы объяснить проблему.

чтобы сохранить данные списка файлов, я создал viewmodel, который в основном представляет собой типизированный список файлов, а также некоторые дополнительные метаданные:

public class ImportDataViewModel
{
    public ImportDataViewModel()
    {
        Files = new List<ImportDataFile>();
    }

    public List<ImportDataFile> Files { get; set; }
...

в представлении, у меня есть форма для просмотра и загрузки файл:

<form action="AddImportFile" method="post" enctype="multipart/form-data">
  <label for="file">
    Filename:</label>
  <input type="file" name="file" id="file" />
  <input type="submit" />
  </form>

представление использует viewmodel в качестве своей модели:

@model MHP.ViewModels.ImportDataViewModel

это отправит файл в мое действие:

public ActionResult AddImportFile(HttpPostedFileBase file, ImportDataViewModel importData)
    {

        if (file.ContentLength > 0)
        {
            ImportDataFile idFile = new ImportDataFile { File = file };
            importData.Files.Add(idFile);
        }

        return View("DataImport", importData);
    }

это действие возвращает представление для страницы DataImport вместе с экземпляром viewmodel, содержащим список файлов.

это прекрасно работает до определенного момента, я могу просматривать файл и загружать его, и я могу видеть данные viewmodel внутри действия, а затем, если я помещу точку останова внутри представления и отладки "этот.Модель", все в порядке.

но тогда, если я попытаюсь загрузить другой файл, при установке точки останова внутри действия AddImportFile параметр importData пуст. Таким образом, представление явно не передает текущий экземпляр своей модели действию.

в образцах MVC, которые я прошел, экземпляр модели "волшебным образом" передается методу действия в качестве параметра, так почему же он пуст сейчас?

Я предполагаю, что реальная проблема-моя ограниченная понимание MVC, и что, вероятно, есть очень простое решение для этого. В любом случае, я был бы очень благодарен, если бы кто-нибудь мог указать мне в правильном направлении.

2 ответов


прошло некоторое время с тех пор, как я опубликовал вопрос, который был довольно окрашен моим небольшим опытом и знаниями MVC. Тем не менее я получил довольно полезный вклад, что в конечном итоге привело меня к поиску решения, а также получить некоторое представление о MVC.

что меня в первую очередь сбило с толку, так это то, что у вас может быть контроллер со строго типизированным объектом в качестве параметра, например:

public ActionResult DoSomething(MyClass myObject)...

этот объект возник из того же контроллер:

...
return View(myObject);
...

прочитав о привязке модели, я понял, что это, конечно, не так. Вид полностью мертв и статичен, и если вы не храните информацию где-то, она исчезла.

возвращаясь к проблема, которая заключалась в выборе и загрузке файлов с клиента и создании списка этих файлов для отображения, я понял, что в целом существует три способа хранения информации между запросами в MVC:

  1. вы можете хранить информацию в полях формы в представлении и отправлять ее обратно на контроллер позже
  2. вы можете сохранить его в каком-то хранилище, например, в файле или базе данных
  3. вы можете хранить его в памяти сервера, обрабатывая объекты который живет во всех запросах, например переменные сеанса

в моем случае у меня было в основном два типа информации для сохранения: 1. Файл метаданных (имя файла, размер файла и т. д.) 2. Содержимое файла

подход "по книге", вероятно, будет заключаться в хранении метаданных в полях формы и содержимого файла в файле или в БД. Но есть и другой путь. Поскольку я знаю, что мои файлы довольно малы, и их будет только несколько, и это решение никогда не будет быть развернутым в ферме серверов или аналогичном, я хотел изучить опцию #3 переменных сеанса. Файлы также не интересны для сохранения после сеанса - они обрабатываются и отбрасываются, поэтому я не хотел хранить их в своей БД.

после прочтения этой прекрасной статьи: доступ ASP.NET данные сеанса с использованием Dynamics

Я был убежден. Я просто создал класс sessionbag, как описано в статье, а затем я мог бы сделать следующее мой контролер:

    [HttpPost]
    public ActionResult AddImportFile(HttpPostedFileBase file)
    {

        ImportDataViewModel importData = SessionBag.Current.ImportData;
        if (importData == null) importData = new ImportDataViewModel();

        if (file == null)
            return RedirectToAction("DataImport");

        if (file.ContentLength > 0)
        {
            ImportDataFile idFile = new ImportDataFile { File = file };
            importData.Files.Add(idFile);
        }

        SessionBag.Current.ImportData = importData;

        return RedirectToAction("DataImport");
    }

я полностью осознаю, что в большинстве случаев, это будет плохим решением. Но для нескольких КБ серверной памяти файлы занимают и с простотой всего этого, я думаю, что это сработало очень хорошо для меня.

дополнительный бонус использования SessionBag заключается в том, что если пользователь ввел другой пункт меню, а затем вернулся, список файлов все равно будет там. Это не так, например, при выборе полей формы / хранилища файлов выбор.

в качестве последнего замечания я понимаю, что SessionBag очень легко злоупотреблять, учитывая простоту использования. Но если вы используете его для того, для чего он предназначен, а именно для данных сеанса, я думаю, что это может быть мощным инструментом.


Загрузка

1) возможно, рассмотрим загрузчик AJAX с HTML, чтобы позволить вашему пользователю выбрать несколько файлов до они отправляются на сервер. Этот загрузчик файлов BlueImp jQuery AJAX довольно потрясающий с довольно отличным api:Загрузка Файла JQuery Blueimp. Это позволит пользователям перетаскивать или выбирать несколько файлов и редактировать порядок файлов, включать/исключать и т. д.. Затем, когда они счастливы, они могут нажать upload to sent к контроллеру или обработчику загрузки для обработки на стороне сервера.

2) Вы можете заставить каждую загрузку сохраняться в базе данных, хотя вы будете перезагружать всю страницу и писать дополнительную модель представления и код бритвы для достижения эффекта листинга. Это, вероятно, не будет реагировать...

относительно сохранения состояния WebForms / MVC

сохранение состояния между запросами несколько черная магия и вуду. Когда идти в ASP.NET MVC, идите в него, понимая, что веб-приложения взаимодействуют с помощью запроса и ответов. Так что идите в обнимку с сетью как без гражданства и развивайтесь оттуда! Когда ваша модель публикуется через контроллер, это ушел вместе с любыми переменными в контроллере! Однако, прежде чем он исчезнет, вы можете сохранить его содержимое в базе данных для последующего извлечения.

веб-приложения не могут сохранять истинное состояние, как настольные приложения. Существует много способов AJAX-фреймворков, а некоторые инструменты вуду, которые люди используют для имитации состояния в среде http. А симуляция состояния на самом деле лишь ложная имитация статичности. ASP.NET веб-формы пытаются имитировать состояние как можно лучше, скрывая от разработчика природу http без состояния. Вы можете столкнуться с большой головной болью при попытке использовать свой собственный код AJAX в тандеме с кодом разметки веб-форм и собственной платформой Ajax.

Я очень рад, что вы учитесь В MVC

все шутки в сторону, если вы получите менталитет MVC/HTTP / Statelessness, будет очень легко применить шаблоны к другим супер популярным фреймворкам, таким как Ruby on Rails, SpringMVC (java), Django (python), CakePHP и т. д... Эта простая передача знаний поможет вам стать намного лучшим разработчиком и стать действительно хорошим в Ajax.

Я очень рад, что вы изучаете MVC 3, я был с несколькими стажировками в некоторых очень больших фирмах, которые имели эти сумасшедшие большие ASP.NET полотно Формы проектов с кодом летают повсюду, просто чтобы изменить несколько числовых значений в базе данных ( - _ - ' ), чувствовал, что я использую ножницы, чтобы связать носок ребенка. Одно неверное движение-и все рухнуло. Это было похоже на разработку в PHP, вы выходите потным и не совсем уверены, что произошло и на какой линии. Отладка и обновление были практически невозможны.