I was presented with an interesting issue in an ASP.NET MVC 2 application. Basically, I had a strongly-typed partial view that submitted data. In addition to consuming, validating, and transmitting its model to the controller, the partial view also needed to pass some "loose" data from its parent view through to the controller as well.
This is interesting because, looking back over all the old MVC code I had written, I've never before had a partial view that submitted data. But submittals from a partial shouldn't be any different than a normal view, so I didn't think anything of it. However, a few hours later, when I was still neither successfully passing in nor returning information from my controller, I began to question whether or not submitting data from a partial view was a good idea at all.
Turns out, it's really not, but I'll still go ahead and describe the work around anyway. The reason I wouldn't recommend submitting data form a partial is because if two or more of them wind up on the same parent view, you'll get an invocation of the respondent controller's ActionResult for each instance of the partial. For example, consider a view bound to a model that has a collection of child models. For this example, let's say it contains three items. If we use a for loop to render a partial for each child model, we'll get three HTML forms. The problem is that even if the user only fills out one of the forms, you'll get three calls to the controller, resulting in duplicate data.
The first approach I attempted was to use the overload to the HTML.RenderPartial method that sets the model for the specified partial view, as well as passes in a ViewDataDictionary to hold the aforementioned "loose" values. This kind of didn't work at all. At first, the ViewDataDictionary was empty in the controller. Then, after some tweaking, I got further, or actually less further, as the controller's ActionResult stopped firing altogether after a form submittal. Usually when you screw up a route like this in MVC, you get either the generic "Resource cannot be found" error page, or an exception is thrown, depending on how offensive your bug is. However, in my case, the page spun and refreshed while the controller just silently failed, leaving me nothing to work with.
So I switched gears and changed my HTML.RenderPartial method to an HTML.RenderAction, specifying the name of my partial view, the controller to use for rendering, and the anonymous type that maps to the controller's ActionResult parameters. I've always used RenderPartial to, well, render partial views; RenderAction was reserved for edge cases when I had to creatively do some code-behind-ish typed things (a la web forms) to get the desired HTML on my MVC page.
Like I said, it took me some time to convince myself to attempt this method. Why? Because, although the anonymous type satisfies the "loose" parameters, what about the model? Here's the signature of my controller's ActionResult:
Since the first argument above is a model, how does that match up to the following invocation - that works - called from the parent view?
The answer is by the magic of MVC. All we have to do is add the following "default" ActionResult:
And the partial view will load. The magic comes into play when the form is submitted, as it takes the model from the post, and maps that, along with the values of the anonymous type, appropriately to the method arguments. So don't psyche yourself out like I did, comparing the parameters set in a proper call to RenderAction a bit too literally to a controller's ActionResult's signature. As long as you have everything wired up correctly, MVC will make sure the post, the model, and the loose parameters all make their way to the server.
So my take-away is this: only use partial views for displaying data. Although it's not that hard, it's still a bit involved to wire everything up correctly in order to render partials that "support" form submittals. And since this wiring can easy get hacky, be careful. MVC is such a clean design pattern that it inspires an attitude in me where if something I'm doing just feels wrong, then there's probably a better way to accomplish it.