在 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
实际上表示某种脏/乐观访问。
有人能证实吗?
我怀疑最后一个是正确的,基于 自定义会话提供程序文档 - 如果是的话实施情况如何?写入“只读”会话是否会带来并发错误(即最后一次写入获胜)的风险,或者是否会带来会话损坏和异常中断的风险?
更新
看起来这是设计使然(来自 Microsoft 的文档):
请注意,即使 EnableSessionState 属性标记为 只读,同一应用程序中的其他 ASP.NET 页面可能能够 写入会话存储,因此请求只读会话数据 存储中的数据可能仍会等待锁定的数据被释放。
看起来上面的第二个选项实际上就是这样做的——会话被锁定,模式更改为可写。
I've come across a curious behaviour of ASP sessions. You can force a controller to be outside of the user's session - I want to be able to do this so that multiple requests can execute at the same time and using a session causes them to execute consecutively.
Disabling session state works as expected:
[SessionState(SessionStateBehavior.Disabled)]
public class SampleController : Controller
{
public ActionResult Test()
{
// Access to the session should be denied
object test = Session["test"];
return Content(test);
}
}
Going to ~/Sample/Test will throw a System.Web.HttpException
, as expected.
However, read-only sessions appear to behave a little strangely:
[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);
}
}
So now I expect ~/Sample/Test to work, and it does. The odd bit is that the set does too: I go to ~/Sample/SetTest?value=foo and it doesn't throw an exception, in fact it returns "foo". If I call ~/Sample/SetTest?value=bar and then ~/Sample/Test I get "bar", indicating that the session has been written to.
So in a SessionStateBehavior.ReadOnly
I have successfully written to the session and read my value back.
I think this could be due to one of three things:
- In MVC 3
[SessionState(SessionStateBehavior.ReadOnly)]
is broken/ignored. - The
[SessionState]
is overridden when the session is written to and becomes writeable. - The
SessionStateBehavior.ReadOnly
actually indicates some kind of dirty/optimistic access.
Can anyone confirm?
I suspect the last one is true, based off the custom session provider documentation - if it is then how does the implementation work? Does writing to a 'read only' session risk concurrency errors (i.e. last write wins) or does it risk corrupt sessions and breaking exceptions?
Update
It looks like this is by design (from Microsoft's docs):
Note that even if the EnableSessionState attribute is marked as
ReadOnly, other ASP.NET pages in the same application might be able to
write to the session store, so a request for read-only session data
from the store might still end up waiting for locked data to be freed.
It looks like the second option above is what it actually does - the session is locked and the mode changed to writable.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
~/Sample/SetTest?value=foo
是的,它不会抛出任何错误,但它也不会在请求结束时保留会话。根据设计,您写入会话的任何内容都会在请求生命周期的最后更新(仅当会话可写时)。
在我的测试中 ~/Sample/Test 什么也没有返回。
我认为当会话为只读时,他们应该在这里快速失败。
顺便说一句,你的样本需要重写
~/Sample/SetTest?value=foo
Yes it won't throw any error, but it also didn't persist the session at the end of the request. By design any thing that you write to session gets updated (only if the session is writable) at the very end of the request life-cycle.
In my test ~/Sample/Test returns nothing.
I think they should have failed fast here when the session is readonly.
By the way your sample need to be rewritten