ASP.Net MVC, Windsor and some Singleton trouble
What?
I just managed to create Stormwind.Accuracy demo app using ASP.Net MVC (more on that later).
The first thing I setup in any project I do is an IoC container. I won't do code without it unless it's a REALLY simple spike. Period.
So, there I go setting my MVC app in a way that it uses Windsor to get the controllers and everything under them. Fine, works like a charm. In theory.
I have an url that looks like: http://localhost:9999/Posts/View/1, where 1 is the id of the post (yeah blog engine, not very original, I know!).
It works fine. Then I tried http://localhost:9999/Posts/View/2. I got the same post as before. Wait, there's something wrong! Let's debug that!
I have this action in PostController:
public ActionResult View(int id){
//Retrieves post and returns View();
}
To my complete and utter surprise, id was being passed as 1 in both requests. "Probably some IIS issue. Let's restart IIS." Nothing.
Ok, probably the routes are wrong. Let's check the Route Values Dictionary:
? this.ControllerContext.RouteData.Values.Keys
Count = 3
[0]: "id"
[1]: "controller"
[2]: "action"
? this.ControllerContext.RouteData.Values.Values
Count = 3
[0]: "2"
[1]: "Post"
[2]: "View"
What??? So it is getting the right value for Id from the route! At this point my colleagues started noticing a big "?" in my forehead.
The Light
That's the point where you keep scratching your head and then it hits you.
How does the MVC framework invoke actions. My guess was that it stores in a table somewhere the controller, action and parameters to invoke with. The issue here is that it stores this data in the actual controller instance.
Usually that's not a problem, since ASP.Net MVC will create a new instance every time it needs to call an action.
Remember that I'm using Windsor to resolve it, though. By default, the lifestyle of my controllers are singleton. I won't discuss here whether they should or shouldn't be singletons, even though I think there is no good reason why they can't be.
Conclusion
Changing the lifestyle to Transient or PerWebRequest did the trick.
Bottomline: If using Windsor to resolve your controllers, STAY AWAY FROM SINGLETONS!