Запись в сеанс только для чтения в MVC 3+ - PullRequest
27 голосов
/ 20 января 2012

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

Отключение состояния сеанса работает как положено:

[SessionState(SessionStateBehavior.Disabled)]
public class SampleController : Controller
{
    public ActionResult Test() 
    {
        // Access to the session should be denied
        object test = Session["test"];
        return Content(test);
    }
}

Переход к ~ / Sample / Test выдаст System.Web.HttpException, как и ожидалось. Однако сеансы только для чтения ведут себя немного странно:

[SessionState(SessionStateBehavior.ReadOnly)]
public class SampleController : Controller
{
    public ActionResult Test() 
    {
        // Read from the session should be fine
        object test = Session["test"];
        return Content(test);
    }

    public ActionResult SetTest(string value) 
    {
        // Write to the session should fail 
        Session["test"] = value;

        // Read it back from the session
        object test = Session["test"];
        return Content(test);
    }
}

Так что теперь я ожидаю, что ~ / Sample / Test будет работать, и это работает. Странный бит в том, что набор тоже делает: я перехожу на ~ / Sample / SetTest? Value = foo , и он не выдает исключение, фактически он возвращает "foo". Если я вызываю ~ / Sample / SetTest? Value = bar , а затем ~ / Sample / Test , я получаю "bar", указывая на то, что сеанс был записан.

Таким образом, за SessionStateBehavior.ReadOnly я успешно записал сеанс и прочитал свое значение обратно.

Я думаю, это может быть связано с одной из трех вещей:

  • В MVC 3 [SessionState(SessionStateBehavior.ReadOnly)] не работает / игнорируется.
  • [SessionState] перезаписывается, когда сеанс записывается, и становится доступным для записи.
  • SessionStateBehavior.ReadOnly фактически указывает на какой-то грязный / оптимистичный доступ.

Кто-нибудь может подтвердить?

Я подозреваю, что последний верен, основываясь на документации пользовательского поставщика сеансов - если это так, то как работает реализация? Риск записи в сеанс «только для чтения» риска параллелизма (т. Е. Выигрывает последняя запись) или риск повреждения сеансов и нарушения исключений?

Обновление

Похоже, что это дизайн (из документов Microsoft ):

Обратите внимание, что даже если атрибут EnableSessionState помечен как ReadOnly, другие страницы ASP.NET в том же приложении могут запись в хранилище сеансов, поэтому запрос данных сеанса только для чтения из хранилища может остаться в ожидании освобождения заблокированных данных.

Похоже, что второй вариант выше - это то, что он на самом деле делает - сеанс заблокирован и режим изменен на доступный для записи.

1 Ответ

10 голосов
/ 20 января 2012

~ / Sample / SetTest? Value = foo

Да, он не выдаст никакой ошибки, но также не сохранил сеанс в конце запроса.Любая вещь, которую вы записываете в сеанс, обновляется (только если сеанс доступен для записи) в самом конце жизненного цикла запроса.

В моем тесте ~ / Sample / Test ничего не возвращает.

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

Кстати, ваш образец нужно переписать

string test = (string)this.Session["test"]; 
...