ASP.NET MVC, session state and concurrent requests: not what you’d expect September 28, 2010
Using ASP.NET’s session storage and management providers for web applications is a no-brainer. User’s preferences, external API access tokens, uploaded documents, you name it, it usually makes sense. We’ll move it into the database when it gets too big, right?
Our new photo book creation and printing service, Poyomi (a little tech intro) uses the session state via MVC’s wrapper class HttpSessionStateBase
which is provider as the SessionData
property on a MVC controller. We store pretty much everything before the finished photo book is assembled: cover design, book’s designed pages, photo assembly preferences, perhaps an access token for flickr or SmugMug…
Poyomi has to render many preview images for a client, doing it so asynchronously by offloading the rendering work to backend servers. A single page’s design and contained photos come from a serialized object in the session itself, that is then transferred via AMQP to the queue processor. All the MVC web app has to do is to wait for the response and pass it over to the client.
Since each photo book contains many pages, browsers will try to load images using multiple concurrent requests at the same time. That shouldn’t be a problem for the massively threaded queue processor and a simple MVC app, right?
Unfortunately, no. All of the little thumbnails were being loaded sequentially and the backend was doing just a single rendering job at a time. What was going on? I took a look at IIS’ requests page (IIS manager > Home > IIS section > Worker Processes > Right click on the Pool > View Current Requests).
Huh? A single request at a time. Talk about abysmal performance.
More consequences on typical ASP.NET MVC websites
AJAX requests often get used to offload time intensive operations. In case all of your HTTP requests, AJAX or not, demand the usage of the session data, they will all block each other. In case the user decides to “cancel” the current background operation by clicking on a link to another page on your site, the execution of it will be delayed until all of the existing requests finish processing.
ASP.NET’s session state
Digging and debugging revealed that it all has to do with the way ASP.NET handles session access. You can read about it more at MSDN.
By default, no concurrent access to the session state is allowed. Even read-only requests (as far as the session is concerned) will be locked exclusively to prevent potential corruption of its state. There is a global or per-ASPX-page setting called EnableSessionState
to alter this behavior: either by disabling the session state altogether… which isn’t really useful in our case… or by marking certain pages as being read-only and thus enabling parallel execution of read-only requests. Yay! But what about our cool and modern ASP.NET MVC 2 application?
Well, it can be done. But doing so requires a visit to the MvcFutures department. I’ve found a single lone blog post that describes the required changes to your MVC execution flow – presumably by a coworker of the one that programmed the solution. Essentially, it implements a new controller factory that is able to set the session state mode per the controller being executed.
Setting the session state mode in ASP.NET MVC 2
- Download the MvcFutures library. Add a local reference to the
Microsoft.Web.Mvc.dll
library. -
Add the module into your project’s
Web.config
to load the dynamic session controller factory. Add the highlighted lines:<httpModules> <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add name="MvcDynamicSessionModule" type="Microsoft.Web.Mvc.MvcDynamicSessionModule, Microsoft.Web.Mvc, Version=2.0.0.0"/> </httpModules> <modules runAllManagedModulesForAllRequests="true"> <remove name="ScriptModule"/> <remove name="UrlRoutingModule"/> <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add name="MvcDynamicSessionModule" type="Microsoft.Web.Mvc.MvcDynamicSessionModule, Microsoft.Web.Mvc, Version=2.0.0.0"/> </modules>
Add this module after the routing module.
-
Tell MVC to use the new dynamic session controller factory by instantiating and assigning it in your
Global.asax.cs
file:protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory(new MvcDynamicSessionControllerFactory()); }
-
Use the session state attribute on your controller:
[ControllerSessionState(ControllerSessionState.ReadOnly)] public class AjaxReadonlyController : Controller {
Other state modes are:
Required
(equivalent toDefault
),ReadOnly
andDisabled
.
Enjoy your high-performance website!
Using Autofac with DynamicSessionControllerFactory
If you are using Autofac for dependency injection (and why aren’t you?) you’ll have to nest the two controller factories. Global.asax.cs
‘ Application_Start
:
var factory = new AutofacControllerFactory(ContainerProvider); var dyn = new MvcDynamicSessionControllerFactory(factory); ControllerBuilder.Current.SetControllerFactory(dyn);
Also, be warned that you cannot inject the session data object into your classes anymore. For example, if you were using something akin to:
var builder = new ContainerBuilder(); builder.Register(s => HttpContext.Current.Session).As().HttpRequestScoped();
…then this won’t work anymore. The controller’s SessionData
property is null until MVC gets around to executing your method. You’ll have to pass it to instances that were already instantiated by Autofac’s controller factory at execution time.
In conclusion
I’m sure that almost every MVC project uses the session for storage of little tokens, strings, counters… which by default blocks the execution of parallel requests. Surprisingly, almost no one blogged about this before. Hopefully this article will add some exposure to this problem.
All of this applies to ASP.NET MVC 2, the latest production ready version. Please let me know if this is going to be implemented in MVC 3 without the usage of MvcFutures!
You stated this fantastically.
Thats why here we Describe all review of each laptop. If you head to the store they are usually called ring cushions. ” Given that the parajumpers ski wear was incorporated as recently as 2005 investors should be impressed with Seadrill’s ability to grow and manage such substantial assets. That little piece of label that I stick onto my kids shoes, school bags,parajumpers outerweargfdddz5482, school uniforms,Parajumpers Outletgfdddz5482, tumblers, lunch boxes and more help me organize my childre
ï¼•ï¼æ³ä»£ã®ç®¡ç†è·ã‚’全員ã€ç¦å³¶çœŒã«ç•°å‹•ã•ã›ã‚‹ã¨ã„ã†æ±äº¬é›»åŠ› [url=http://www.funtimebr.com/]グッムãƒãƒƒã‚° アウトレット[/url] ã®ç•°ä¾‹ã®äººäº‹ç–ãŒã€ç¤¾å†…å¤–ã§æ³¢ç´‹ã‚’呼んã§ã„る。ç¦å³¶ç¬¬ï¼‘原å力発電所 [url=http://www.funtimebr.com/]グッム店舗[/url] 事故当時ã®é¦–è„³ã¯æ—¢ã«é€€é™£ã—ãŸãŒã€å›½è²»ã®è¿½åŠ æŠ• [url=http://www.funtimebr.com/]http://www.funtimebr.com/[/url] 入をå—ã‘ã€å½“æ™‚ï¼•ï¼æ³ä»¥ä¸Šã®ç®¡ç†è·ã¾ã§ä¸€å®šã®è²¬ä»»ã‚’è² [url=http://www.audreyisher.name/]アグ 店舗[/url] ã‚ã•れる形ã¨ãªã£ãŸã‹ã‚‰ã 。厳ã—ã™ãŽã‚‹äººäº‹ç–ã¯å£«æ°—ã®ä½Žä¸‹ã‚’æ‹›ãæã‚Œã‚‚ã‚る。「進é§è»ã«ã‚ˆã‚‹å®ˆæ—§æ´¾ [url=http://www.audreyisher.name/]アグ アウトレット[/url] ã®ä¸€æŽƒã€‚ã“ã“ã¾ã§ã‚„ã‚‹ [url=http://www.audreyisher.name/]http://www.audreyisher.name/[/url] ã¨ã¯â€¦ã€ã€‚エãƒãƒ«ã‚®ãƒ¼æ¥ç•Œã®é–¢ä¿‚者ã¯çµ¶å¥ã™ã‚‹ã€‚æ±é›» [url=http://www.pecye.net/]ケイトスペード 財布[/url] ã®ç¾åœ¨ã®ç·åˆç‰¹åˆ¥äº‹æ¥è¨ˆç”»ï¼ˆå†å»ºè¨ˆç”»ï¼‰ã¯å¹³æˆï¼’ï¼”å¹´ï¼•æœˆã«æ”¿åºœèª [url=http://www.pecye.net/]ケイトスペード 新作[/url] 定ã•ã‚Œã€æ±é›»ã¯å®Ÿè³ª [url=http://www.pecye.net/]http://www.pecye.net/[/url] 国有化ã•れãŸã€‚当時ã®å‹ä¿£æ’久会長ら経営陣ã®å¤§åŠãŒé€€ä»»ã—ã€å–ç· å½¹ã®éŽåŠæ•°ã¯ç¤¾å¤–å– [url=http://www.auroralimofl.com/]SEIKO 腕時計[/url] ç· å½¹ã«ã€‚退任ã—ãŸçµŒå–¶é™£ã¯æ±é›»æœ¬åº—ã®å»ºç‰©ã«å…¥ã‚Œãªããªã‚Šã€ [url=http://www.auroralimofl.com/]SEIKO 腕時計[/url] 影響力ã¯ãªããªã£ãŸã€‚ãã®ä»£ã‚り経済産æ¥çœã‚„原å力æå®³è³ å„Ÿæ”¯æ´æ©Ÿæ§‹ã®æ„ [url=http://www.auroralimofl.com/]http://www.auroralimofl.com/[/url] å‘ãŒå¼·ãåæ˜ ã•れるよã†ã«ãªã£ãŸã€‚
  ã•らã«ã€å¾“æ¥å“¡ã®çµ¦ä¸Žã‚’管ç†è·ã¯ï¼“割ã€ä¸€èˆ¬è·ã¯ï¼’å‰²å‰Šæ¸›ã€‚ä¸€èˆ¬è· [url=http://www.rodfincannon.com/]ケイトスペード 財布[/url] ã¯æ®‹æ¥æ‰‹å½“ãªã©ãŒã¤ããŸã‚ã€ä¸€éƒ¨ [url=http://www.rodfincannon.com/]ケイトスペード 財布[/url] ã§ã¯ç®¡ç†è·ã¨ä¸€èˆ¬è·ã§çµ¦ä¸Žã®é€†è»¢ç¾è±¡ãŒèµ·ãã€ç®¡ç†è·ã® [url=http://www.rodfincannon.com/]http://www.rodfincannon.com/[/url] 退è·ãŒæ€¥å¢—ã—ãŸã€‚æ±é›»ã¯ç®¡ç†è·ã‚’㤠[url=http://www.lipsynctv.com/]coach 財布[/url] ãªãŽç•™ã‚ã‚‹ãŸã‚ã€ä»Šå¤ã«ã¯ï¼‘人1ï¼ä¸‡å††ã®ä¸€æ™‚金を支給ã—ãŸã»ã©ã 。新計画ã§ã¯ã€ [url=http://www.lipsynctv.com/]coach ãƒãƒƒã‚°[/url] 国費ã®ã•らãªã‚‹æŠ•入をå—ã‘ã€ä¸€éƒ¨ã®ç¤¾å¤–å–ç· å½¹ã‹ã‚‰äº‹ [url=http://www.lipsynctv.com/]http://www.lipsynctv.com/[/url] 故当時ã®ç®¡ç†è·ã¸ã®è²¬ä»»è¿½åŠã‚’求ã‚る声ãŒå¼·ã¾ã£ãŸã¨ã„ã†ã€‚実際ã€å‹ä¿£å‰ä¼šé•·ã‚‰ã®è–«é™¶ã‚’å—ã‘ãŸï¼•ï¼æ³ [url=http://www.brcustomwoodwork.com/]ケイトスペード アウトレット[/url] 代ã®ç®¡ç†è·ã‚’本店ã‹ã‚‰å¤–ã™ã“ã¨ã§ [url=http://www.brcustomwoodwork.com/]ケイトスペード 財布[/url] ã€ã€Œâ€œå®ˆæ—§æ´¾ä¸€æŽƒâ€ãŒå®Œäº†ã™ã‚‹ã€ã¨ [url=http://www.brcustomwoodwork.com/]http://www.brcustomwoodwork.com/[/url] ã®è¦‹æ–¹ã‚‚ã‚る。ç¦å³¶ [url=http://www.gatewaychurchsbc.org/]グッムãƒãƒƒã‚°[/url] 転勤をå—ã‘入れられãšã€é€€è·ã‚’é¸ã¶äººã‚‚ã„ã‚‹ã¨ã¿ã‚‰ã‚Œã‚‹ã€‚ãŸã ã€å޳ã—ã™ãŽã‚‹äººäº‹ ç–ã¯ç¤¾å“¡å£«æ°—を下ã’ã¦ã—ã¾ã†ã€‚ç¦å³¶ã«æ´¾é£ã•れる「元管ç†è·ã€ã®çµ¦ä¸Žã¯ç¾åœ¨ã‚ˆã‚Šä¸Šç© [url=http://www.gatewaychurchsbc.org/]グッムアウトレット[/url] ã¿ã•れるよã†ã ãŒã€å½¼ã‚‰ã®ã‚„る気を失ã‚ã›ãªã„工夫 [url=http://www.gatewaychurchsbc.org/]http://www.gatewaychurchsbc.org/[/url] も求ã‚られãã†ã 。
You definitely made your point.
Souls in the Waves
Superior Morning, I just stopped in to go to your internet site and imagined I would say I enjoyed myself.
Awesome facts, Thank you!
Nicely put. Appreciate it.
Canada Goose
Wow tons of useful info!
You actually mentioned this perfectly!
Truly plenty of helpful data.
Valuable forum posts, Many thanks.
You reported this adequately!
Click on any tag to get a stream of tweets on that subject. If you’re lucky enough to enjoy a white Christmas,parajumpers outerwear,, you may also be plagued by slippery or icy roads and pavements when all that snow starts to melt. “As a former grains specialist I couldn’t agree with you less. It is important to know the pore sizes of this particular desiccant before you decide to put it to use. 00 The bag is a cassic of the Parajumpers Outlet tave bag coection,,Parajumpers Outlet,this smaest ve
Many thanks. I like it.
You actually stated it terrifically!
Wonderful info Kudos!
Awesome material, Appreciate it!
Cheers, Lots of stuff!
Kudos! A lot of forum posts!
Valuable forum posts, Thanks a lot!
You actually said that wonderfully!
Canada Goose Jackor
Kudos! Ample data!
Kudos. A good amount of advice.
Many thanks! I like this!
You actually explained that adequately!
Nicely put. Kudos!
Position certainly utilized!.
Wow many of helpful facts.
Whoa loads of good knowledge!
Fantastic stuff. With thanks!