ASP.NET MVC - Совместное использование состояния сеанса между контроллерами - PullRequest
6 голосов
/ 11 августа 2009

Я все еще в основном незнаком с Инверсией Контроля (хотя я узнаю об этом сейчас), поэтому, если это решение моего вопроса, просто дайте мне знать, и я вернусь к изучению этого вопроса.

У меня есть пара контроллеров, которые нуждаются в переменной Session, естественно, ничего особенного не произошло из-за того, как Session работает в первую очередь, но это заставило меня задуматься о том, каков самый чистый способ разделения связанных объектов между двумя отдельными контроллерами , В моем конкретном сценарии у меня есть UploadController и ProductController, которые работают вместе для загрузки файлов изображений. Поскольку файлы загружаются UploadController, данные о загрузке сохраняются в сеансе. После этого мне нужно получить доступ к этим данным Session в ProductController. Если я создам свойство get / set для переменной Session, содержащей информацию о моей загрузке на обоих контроллерах, я смогу получить доступ к этим данным, но в то же время я буду нарушать все виды DRY, не говоря уже о создании, в лучшем случае запутанный дизайн, в котором объект разделяется и изменяется двумя полностью отключенными объектами.

Что вы предлагаете?

Точный контекст:

Загрузка файла Просмотр публикует файл в UploadController.ImageWithpreview (), который затем считывает опубликованный файл и копирует его во временный каталог. После сохранения файла другой класс создает эскиз загруженного изображения. Путь как к исходному файлу, так и к сгенерированной миниатюре затем возвращаются с помощью JsonResult в обратный вызов javascript, который обновляет некоторое динамическое содержимое в форме на странице, которая может быть «сохранена» или «отменена». Сохранено ли загруженное изображение или оно пропущено, мне нужно либо переместить, либо удалить как его, так и созданный эскиз из временной директории. Для этого UploadController отслеживает все загружаемые файлы и их миниатюры в поддерживаемом сеансом объекте Queue.

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

Ответы [ 2 ]

3 голосов
/ 11 августа 2009

На ум приходит пара решений. Вы можете использовать класс «SessionState», который отображается в запрос и получает / устанавливает информацию как таковую (я делаю это из памяти, так что это вряд ли скомпилируется и предназначено для передачи смысла):

internal class SessionState
{
  string ImageName
  {
    get { return HttpContext.Current.Session["ImageName"]; }
    set { HttpContext.Current.Session["ImageName"] = value; }
  }
}

А затем из контроллера сделайте что-то вроде:

  var sessionState = new SessionState();
  sessionState.ImageName = "xyz";
  /* Or */
  var imageName = sessionState.ImageName;

В качестве альтернативы, вы можете создать метод расширения контроллера:

public static class SessionControllerExtensions
{
  public static string GetImageName(this IController controller)
  {
    return HttpContext.Current.Session["ImageName"];
  }

  public static string SetImageName(this IController controller, string imageName)
  {
    HttpContext.Current.Session["ImageName"] = imageName;
  }
}

Затем с контроллера:

  this.SetImageName("xyz");
  /* or */
  var imageName = this.GetImageName();

Это, конечно, СУХОЙ. Тем не менее, мне не особенно нравится ни одно из этих решений, так как я предпочитаю хранить как можно меньше данных, если таковые имеются, во время сеанса. Но если вы намерены хранить всю эту информацию без необходимости загружать / распознавать ее из какого-либо другого источника, это самый быстрый (самый грязный) способ, которым я могу придумать. Я совершенно уверен, что есть гораздо более элегантное решение, но у меня нет всей информации о том, что вы пытаетесь сделать и в чем проблема.

Имейте в виду, что при хранении информации в сеансе вам придется обезвоживать / повторно увлажнять объекты посредством сериализации, и вы, возможно, не получаете производительность, которая, как вы думаете, вы делаете, делая это таким образом.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: в ответ на дополнительную информацию Не уверен, где вы собираетесь развернуть это, но обработка изображений «в реальном времени» - верный путь к атаке DoS. Я предлагаю вам следующее - это предполагает, что это публичное лицо, и любой может загрузить изображение:

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

2) Обработайте эти изображения и во время обработки отобразите «графическое изображение обработки». У вас может быть запрос ajax на странице продукта, который проверяет обрабатываемые изображения и пытается загружать их каждые X секунд.

3) Пока изображение «обрабатывается», пользователь может отказаться от обработки, предполагая, что именно он загрузил изображение. Это доступно либо на страницах (страницах) продукта, на которых отображается изображение, либо в отдельном представлении «Очередь пользователей», которое позволит им удалить изображение из рассмотрения.

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

images / products / {id} .jpg или, если это коллекция, images / products / {id} / {sequence} .jpg.

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

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

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

1 голос
/ 11 августа 2009

Есть ли полная эквивалентность между UploadController и ProductController?

Поскольку файлы загружаются с помощью UploadController, данные о загрузке сохраняются в сеансе. После этого мне нужно получить доступ к этим данным сеанса в ProductController.

Когда я прочитал, что для UploadControl требуется доступ для чтения и записи данных загрузки, ProductController требуется только чтение.

Если это так, тогда вы можете прояснить это, используя неизменяемую оболочку вокруг информации о загрузке и заставить UploadController поместить ее в сеанс.

Сама Сессия по определению является общедоступной общей доской объявлений, отделяющей явные отношения за счет разрешения кому-либо получать и размещать. Вы можете позволить ProductController знать о UploadController и, следовательно, устранить необходимость передачи информации о загрузке через сеанс. Мой инстинкт заключается в том, что информация о загрузке интересна для публики, поэтому использование Session целесообразно.

Я не вижу здесь никакого СУХОГО нарушения, мы явно пытаемся разделить обязанности.

...