Rewritten: My original post seemed to be misunderstood. I have since reported it as a bug with the following description. My original post for this question can be found below the second <HR
>.
I have a major issue with POST in a user control.
I have a UserControl which has a controller containing two ActionMethods called 'ContactForm'. The second has ActionVerb.POST on it to respond to the post-back. The user control is primarily used via AJAX - but that actually is irrelevant here. Obviously these action methods render a partial view.
I have a main page containing an additional html form for 'EnterContest'. Again - its controller has two ActionMethods called 'EnterContest', one of which responds to ActionVerb.POST. This view contains the 'ContactForm' in a side bar which is rendered with :
<% Html.RenderAction("ContactUsForm", "Company", new { commentsBoxHeader = "Questions" }); %>
The problem occurs when posting back the 'EnterContest' Form (the main form on the view).
The POST request from Fiddler contains just this query string (obviously not containing any of the POST data from the contact us form because thats a completely separate HTTP ACTION).
contestId=ND09&email=fred&btnEnterContest=Submit
(yes, this looks like a GET but thats what Fiddler shows for a POST too)
First - (as expected) - the 'EnterContest(FormCollection data) method is called in the main controller. This processes the form submission to enter the contest - calls the webservice etc..
Second - (NOT expected) - The POST method of the 'ContactForm' controller is called. This immediately crashes because it is missing expected parameters - and we don't want it called anyway. This happens during the same Http request.
If I take a look at the stack trace - it is being called from the dynamically generated aspx page - originating at the Html.RenderAction line of code shown above. So obviously what is happening is the code that is looking to partially render the 'ContactUs' action method looks at the Request and sees there is a method to handle POST so it routes it there - which is VERY BAD. Its probably somewhere around this method in the framework :
System.Web.Mvc.dll!System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod
This behavior is VERY confusing and really breaks what seemed to be a simple page. I'm pretty sure it is a bug - because I cannot see an elegant work around without some really clumsy checking in my controller. I think RenderAction is in futures - but I don't know if the issue is present there or in the main framework.
Just to clarify what is NOT happening :
- any clever jQuery
- more than one HTTP request (verified in Fiddler)
- nested forms
Thanks
Original post
I am using the RenderAction
Html extension in ASP.NET MVC.
I came across something unexpected, but which is making more sense as I think about it.
Lets say I have a view containing a 'RenderAction' method to generate the contact for a part of the page.
<% Html.RenderAction("ContactUsForm", "Company",
new { commentsBoxHeader = "Questions" }); %>
In this case the partial view it generates creates an ajax form which posts back via <%= Html.BeginAjaxForm() %>
.
So of course I need an actionresult to handle the AJAX postback.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ContactUsForm(FormCollection formdata)
Now the problem occurs when the parent view containing this partial render action has a normal (non-ajax) form with a POST action. What happens is that the POST method for the ContactUsForm
action is call in addition to the POST action for the main view. Inside this action the formdata
property contains all the properties for the parent view - so ContactUsForm
dies with a null reference or something like that.
I've come up with 3 possible solutions :
1) create a different action name for the post back for any user controls on the page. This has the disadvantage that you have to post back to a different function than created the partial view. Often this can be more cumbersome but this is what i'm doing right now.
2) check in every POST method (you'd have to remember to run this check in every user control's POST action method) to see if the form data is intended for that form it, and if not return a default view.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResultContactUsForm(FormCollection formData)
{
if (formData["btnSubmitContactUsForm"] == null) {
// "This form is not for us!";
// figure out how (if is possible) to return the get default view here
// and call it with the right arguments
}
}
3) report it as a bug.
What should I be doing here? I'm leaning towards thinking of this as a bug
Edit: One very important thing I need to stress more is that BOTH POST methods are called - so its not just somethig like a nested form.
Edit 2: In Fiddler I see only one request. The problem is when it tries to render the ContactUsForm
after having already handled the POST for my main page it hits the 'POST' method for 'ContactUsForm' instead of the non-post handler.