ASP.NET MVC 中的 HttpContext.Items
我正在实现我自己的使用单例模式的 ApplicationContext 类。 我想将它的实例存储在 HttpContext.Items 中,因为它可以在请求的所有部分中访问。 我一直在阅读有关在 ASP.NET MVC 中使用 HttpContext 的内容,主要的痛苦之一是它引入了测试复杂性。 我尝试过研究 HttpContext.Items 的可测试性,但我能找到的只是 Session 上的东西。 我发现的唯一内容之一是 Wrox 上的 Professional ASP.NET 3.5 MVC 书中的示例章节(pdf 链接在此)。 第 15 页是这样说的:
你不能使用的东西:HttpContext.Items
在本节的上面,我们坦白告诉您我们对您撒了谎:HttpContext 不在 ASP.NET MVC 和 ASP.NET Web Forms 之间共享。 因此,您无法使用 HttpContext.Items 集合来存储和检索数据位。
这样做的原因是,一旦您重定向到 Controller,您的 HttpHandler 就会变成 System.Web.Mvc.MvcHandler,它是使用 HttpContextWrapper 创建的,它将有自己的 HttpContext.Current 定义。 不幸的是,在这次握手期间,像 HttpContext.Items 这样的东西没有被传输。
这归结为 HttpContext 类型,尽管看起来和听起来都非常相同,但并不相同,并且您不能以这种方式传递数据。
现在,我已经尝试对此进行测试,据我所知,如果您使用 RedirectToAction 重定向到另一个控制器,则 HttpContext.Items 确实会保留。 我使用默认的 ASP.NET MVC 项目来测试这一点。 我所做的是,将此方法添加到 Global.asax.cs:
protected void Application_BeginRequest()
{
Context.Items["Test"] = "Hello World";
}
在 HomeController.cs 中,我已将 Index 方法更改为:
public ActionResult Index()
{
return RedirectToAction("About");
}
并将 About 方法更改为:
public ActionResult About()
{
Response.Write(Convert.ToString(HttpContext.Items["Test"]));
return View();
}
当我运行应用程序时,页面正确重定向到/Home/About 和 Response.Writes 在 global.asax.cs 中设置的正确“Hello World”字符串。
所以,在我看来,当他们说时,我要么不明白这本书的意思 “像 HttpContext.Items 这样的东西不会被传输”或者它确实传输了这些东西并且可以使用 HttpContext.Items。
如果你们建议我避免使用 HttpContext.Items,是否还有另一种替代方法可以在每个请求的基础上跨请求存储对象?
I'm implimenting my own ApplicationContext class that uses the singleton pattern. I want to store my instance of it in HttpContext.Items, since it is accessible in all parts of the request. I've been reading about using HttpContext with ASP.NET MVC and one of the major pains is that it introduces testing complexity. I've tried doing research on the testability of HttpContext.Items, but all I can find is stuff on Session. One of the only things I've found is out of a sample chapter in the Professional ASP.NET 3.5 MVC book on Wrox (pdf link here). On page 15 it says this:
Something You Can’t Use: HttpContext.Items
Above in this section, we came clean and told you that we lied to you: HttpContext is not shared between ASP.NET MVC and ASP.NET Web Forms. As a result of this, you cannot use the HttpContext.Items collection to store and retrieve bits of data.The reason for this is because once you redirect to a Controller, your HttpHandler becomes the System.Web.Mvc.MvcHandler, which is created using HttpContextWrapper, which will have its own definition of HttpContext.Current. Unfortunately, during this handshake, things like HttpContext.Items are not transferred.
What this boils down to is that the HttpContext types, despite looking and sounding very much the same, are not the same, and you cannot pass data in this way.
Now, I've tried testing this out, and as far as I can tell, if you redirect to another controller using RedirectToAction, HttpContext.Items does remain. I'm using the default ASP.NET MVC project to test this. What I've done is, add this method to Global.asax.cs:
protected void Application_BeginRequest()
{
Context.Items["Test"] = "Hello World";
}
And in HomeController.cs, I've changed the Index method to:
public ActionResult Index()
{
return RedirectToAction("About");
}
And changed the About method to:
public ActionResult About()
{
Response.Write(Convert.ToString(HttpContext.Items["Test"]));
return View();
}
When I run the application, the page properly redirects to /Home/About and Response.Writes the correct "Hello World" string set in the global.asax.cs.
So, it seems to me as if I'm either not understanding what the book is meaning when they say
"things like HttpContext.Items are not transferred" OR it does transfer this stuff and it's okay to use HttpContext.Items.
If you guys recommend that I avoid HttpContext.Items, is there another alternative way to store an object across a request on a per-request basis?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我做了一个测试,TempData 确实在会话状态禁用的情况下爆炸了。 我唯一的建议是不要将对象本身存储在临时数据中,而是按照建议存储简单类型的字段。 由于您没有序列化对象树,因此在进程外运行不会对性能产生太大影响。
I did a test and TempData does, indeed, explode with session state disabled. My only advice would be to not store the object itself in temp data but store the simple typed fields as has been suggested. Since you're not serializing object trees it shouldn't be that big of a performance impact running out-of-process.
你的问题问了一些事情,但我认为第 1 项就是你正在寻找的答案。
可以根据每个请求使用
Context.Items
进行缓存吗?是的。 如果在进程中、每个请求、网络场中的每台机器是您的标准,那么 Context.Items 可以满足您的要求。
Context.Items
很难测试吗?就可测试性而言,我会将 Context.Items 隐藏在某种接口后面。 通过这种方式,您无需直接引用 Context.Items 即可获得单元测试功能。 否则,您需要测试 Context.Items 的哪些内容? 该框架将存储和检索值吗? 让您的代码不了解
System.Web
,您就会成为一名快乐的露营者。Context.Items
会在RedirectToAction
中生存吗?不,你的测试无效。 它在每个 Web 请求上设置“Hello, world”,并且您的测试跨越两个 Web 请求。 第一个是调用 Index 操作时。 第二个是调用
RedirectToAction
操作时(它是 HTTP 302)。 要使其失败,请在 Index 操作中设置一个新值,并查看它是否保留在 About 操作中。Your question is asking a few things but I think item #1 is the answer you're looking for.
Is it fine to use
Context.Items
for caching on a per request basis?Yes. If in process, per request, per machine in the web farm is your criteria then Context.Items gives you that.
Is
Context.Items
difficult to test with?As far as testability, I would hide
Context.Items
behind an interface of some sort. This way you get unit testing capabilities without having to referenceContext.Items
directly. Otherwise, what do you need to test aboutContext.Items
? That the framework will store and retrieve values? Keep your code ignorant ofSystem.Web
and you'll be a happy camper.Will
Context.Items
surviveRedirectToAction
?No. Your test is invalid. It's setting "Hello, world" on every web request and your test spans two web requests. The first is when the Index action is called. The second is when
RedirectToAction
action is called (it's an HTTP 302). To make it fail, set a new value in the Index action and see if it's retained in the About action.使用 TempData 字典,它主要用于在 Actions 重定向之间存储对象:
然后在视图中检索值:
Use the TempData Dictionary, it is mainly for storing objects between Actions redirects:
Then retrieve the value in your view: