Запись на сеанс только для чтения в MVC 3+
Я столкнулся с любопытным поведением 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
фактически указывает на какой-то грязный/оптимистический доступ.
Кто-нибудь может подтвердить?
Я подозреваю, что последнее верно, основываясь на пользовательской документации поставщика сеансов - если это так, то как работает реализация? Влияет ли запись на "только чтение" риск concurrency ошибок (т.е. Последних попыток записи) или же он рискует коррумпированными сеансами и нарушает исключения?
Обновление
Похоже, что это по дизайну (из Документов Microsoft):
Обратите внимание, что даже если атрибут EnableSessionState помечен как ReadOnly, другие страницы ASP.NET в одном приложении могут пишите в хранилище сеансов, поэтому запрос данных сеанса только для чтения из хранилища все равно может оказаться в ожидании освобождения заблокированных данных.
Похоже, что второй вариант выше - это то, что он на самом деле делает - сеанс заблокирован и режим изменился на записываемый.
Ответы
Ответ 1
~/Sample/SetTest? value = foo
Да, это не вызовет никакой ошибки, но также не сохранило сессию в конце запроса. По дизайну все, что вы пишете на сеанс, обновляется (только если сеанс доступен для записи) в самом конце жизненного цикла запроса.
В моем тесте ~/Sample/Test ничего не возвращает.
Я думаю, что они, должно быть, быстро потерпели неудачу, когда сеанс читается только.
Кстати, ваш образец должен быть перезаписан
string test = (string)this.Session["test"];