x.BeginForm() and ViewData - asp.net-mvc

I have a view where I initially used Html.BeginForm(). After POSTing, I show a message with ViewData["Message"]. That works fine.
When I change to Ajax.BeginForm(), ViewData["Message"] is null.
What am I missing?

I guess when you use Html.BeginForm your controller is rendering the current View again, so the html will have the message correctly displayed.
When you make Ajax requests is up to you to control what should happen after the request success.
This can be done with the Ajax.BeginForm ajaxOptions parameter, where you can set a javascript callback function at the OnSuccess property.

FWIW, I was just plain doing this wrong. What I wanted to accomplish, and how to, is explained here - http://davidhayden.com/blog/dave/archive/2009/05/19/ASPNETMVCAjaxBeginForm.aspx

Related

A public action method '..' was not found on controller '..'

I wanted to put a random image on every viewpage of my mvc project. So i created a method that returns a partialView and call that method in the shared Layout page.
This works fine when I try to login with a correct username and password. The used is loged in and every page contains a random image. But when I give the invalid combination of username and password. The shared layout page does not find the controller I want to call with my #Html.Action and actualy the login view should be returned with an error message 'invalid combination of username and password' and ofcourse, with the random image.
InnerException:
{"A public action method 'RandomSponsor' was not found on controller 'Project.WebUI.Controllers.HomeController'."}
My Html.Action in shared layout.
#Html.Action("RandomSponsor", "Home")
Method in homecontroller.
[HttpGet]
[ChildActionOnly]
public ActionResult RandomSponsor()
{
var model = service.getRandomSponsor();
return PartialView("RandomSponsor", model);
}
The getRandomSponsor method works fine, this one always returns one random string value that is returned to the RandomSponsor.cshtml view.
RandomSponsor.schtml (only contains the image string)
<img src="~/Content/Images/Advert/#(Model)" alt="a" />
I searched the web for this problem but didn't found a solution, does anyone know the answer to this one?
Might it be something with HttpGet of HttpPost?
Regards.
If the executing request is a POST, then it will try to find a method RandomSponsor accepting HttpPost. If this makes sense, you could remove HttpGet and that should do the trick.
This can also happen if you have many layers of calls that start with a POST (I had an action returning a view returning a partial view calling RenderAction), then the call to RenderAction will still look for a POST method
Very similar to this problem that I had here - How to solve "public action method 'methodActionName' was not found on controller 'controllerNameController'"
And if you want to continue to accept the HTTP GET verb and fix the problem of cascading post request into a get request add this to your method
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
Keep in mind that [HttpGet] is the same as [AcceptVerbs(HttpVerbs.Get)]
This will happen if the request is a POST but the controller method is annotated [HttpGet]. For example, you might issue a POST that returns a view containing partial views called with #Html.Action, using controller methods annotated with [HttpGet]. If the original request is a POST, all of the controller methods subsequently called will need to support POST.
To fix it you can use the AcceptVerbs attribute to specify that your controller method accepts both POST and GET:
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Get)]
Received this error all of the sudden on several different PartialViews (not all of them) when customizing an install of MVCForum. We had not made any changes to the methods or views concerning the errors so it was really frustrating as to why they were broken.
After trying the other solutions on this post and others, went back through the changes made and what ended up stopping the errors was that we had changed the bindings in IIS to another domain that had the 'enforce lower case url' URL Rewrite rule enabled.
When we disabled the enforce lowercase rule, the errors stopped and the site worked as it was supposed to. It's not a URL Rewrite issue (I don't think) because we are able to enforce www using it with no errors. It's a lowercase rewrite issue. Didn't matter if we had the lowercase rule before or after the www rule.
This solution probably doesn't apply to many cases of this error, but it worked for us. Hopefully someone else can benefit from such a simple fix.
I just solved this issue strangely enough on my local PC, by making sure my entire request path was lower case. So give that a try.
I know this is a pretty old thread - but as it's top Google result I thought I'd add a potentially missing link for MVC.Net 5.2.6.
Scenario
I was attempting to call a child action via #Html.Action("ActionName", new { Id = 123})
and received an error much like the above, but none of the other solutions worked. I could hit the controller action externally (i.e. HttpGet), but the child action kept throwing the exception and was driving me nuts!
The solution I found
After two-ing and fro-ing for some time, I started playing with my routing attributes. I had the controller set up as:
[Route("{action}")]
[RoutePrefix("Prefix")]
[RouteArea("AreaName")]
As there was only one public action i wanted, "Index", I removed the {action} and placed an explicit route attribute on the public action and put my ChildActionOnly attribute back on the child.
After I did that, I hit the run and hey presto - the action was hit.
Might be worth a try if you're getting this error while using attribute routing. Note I did attempt to route the child action and this didn't work.
In my case, the same issue was happening randomly with the implicit :
using (Html.BeginForm())
Changing above to :
using (Html.BeginForm("Action","Controller", FormMethod.Post))
fixed this issue.
Did you give it a shot with Html.RenderAction? It is typically faster then Html.Action as it interact directly into the response stream as opposed to building a string.
You can view the following topics for more info:
What is the difference (if any) between Html.Partial(view, model) and Html.RenderPartial(view,model) in MVC2?
Html.Partial vs Html.RenderPartial & Html.Action vs Html.RenderAction
Another thing to note is that for Html.Action or Html.RenderAction, your view doesn't need to be in Shared folder, that is only required if you use Html.Partial or Html.RenderPartial

How can I validate partial view that is returned from controller

I have a view page with ajax.action link which returns a partial view from controller and render it to divid as updated target id. But I could not perform client side validation on that partial view.
Can I have solution for it?
When you load a partial view's html with ajax it is normal for the JavaScript code not to be executed. Especially if you have calls to functions attached to onload event since this event is fired long before the ajax call is executed. Check out this article http://adammcraventech.wordpress.com/2010/06/11/asp-net-mvc2-ajax-executing-dynamically-loaded-javascript/ it describes all sorts of problems that you can have with this approach. If you want a more specific answer it will be good to proivide more info on your setup like - what version of .net/asp.net mvc you are using and what validation framework are you trying to use.

View Master Page and PostBack

I have a dropdown list on my master page that needs to postback after being changed. After the postback, whatever page initiated the postback needs to be re-displayed.
My question is where do I handle this? Obviously I do not want to have to modify every Action in my project... My guess is to maybe postback to some other fixed action and have that action redirect back to the page that is the referrer. Am I correct? Any thoughts?
Thanks.
Jason
In Site.Master, I ended up wrapping the dropdown within its own form that posted back to a dedicated controller/action.
<% Using Html.BeginForm("ChangeRole", "Home")%>
<div id="roleSelector">Change Role: <%=Html.DropDownList("Role", DirectCast(ViewData.Item("Roles"), SelectList), New With {.onchange = "this.form.submit();"})%></div>
<% End Using%>
In the controller I used the following code to change the mode and then redirected back to the referring URL.
<AcceptVerbs(HttpVerbs.Post)> _
Public Function ChangeRole() As ActionResult
Me.CurrentUser.SetRole(DirectCast([Enum].Parse(GetType(Models.ApplicationRoles), Me.Request.Item("Role")), Models.ApplicationRoles))
Return Redirect(Request.UrlReferrer.ToString())
End Function
I am unsure if this is the recommended way but I have been unable to think of another solution.
When you post back from the dropdown list change what are you doing? Can you maybe handle this in a jQuery call thus eliminating the need to re-display the page at all?
Calls to Action Methods can be asynchronous as griegs says, as such, you can post whatever information you need from the radio buttons to an action method without needing to reload the page.
If you need to update a part of the page, you can replace it with the contents of a rendered action method. If you use the jQuery ajax methods, you can post specific information to your methods.
For example, something like this:
$(document).ready(function()
{
$("#myRadioButton").change(function()
{
//Post to your action method, with the value of the radio button, function to call on success
$.post('yourActionMethodUrl', $(this).val(), function()
{
//Update some part of the page
});
});
});
This is based on memory, so you may need to check the syntax.

How can I change the mvc ajax form parameters in the posted-to controller?

For example, if I wanted to change the UpdateTarget or the InsertionMode in the controller after the form was posted.
You can work around this by not setting updatetargetid and insertmode, instead you just need to use onsuccess and oncomplete event, and then when the controller return the value back, you just need to add the targetid and insertmode into the return data (i.e json), then in your function of handling return result, you just need to read these values.
Controller has no information where and how calling JavaScript code is going to insert controller's result into the page. So controller is unable to change it.

POST method called on MVC UserControls as well as their parent views

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.
EDIT2: I just noticed that you are using RenderAction instead of RenderPartial. I suspect what is happening is that it is using the RequestContext of the posted form to choose which ContactUsForm method to choose when the RenderAction is invoked. This is arguably correct behavior since the action is being invoked from a postback, just not the one you intended. I would approach this in a completely different manner. Have the partial generated by a ViewUserControl and include it on the page using RenderPartial instead. Remove the GET ContactUsForm method and only have the POST version. That is, the form itself is generated as a ViewUserControl with markup predetermined or dynamically generated via parameters passed via ViewData. The form response is handled via the controller action.
EDIT: Since you indicate that nesting is not the issue, is it possible that you are using javascript (say jQuery) to trigger the submit and your selector is too broad. If, for example, you had code like the following, that would account for the behavior you are seeing.
$(document).ready( function() {
$('#mybutton').click( function() {
$('form').submit();
});
});
Original answer: (left for context)
It sounds like you have nested forms in your view. Try moving the RenderAction outside the form in the parent view and see if that fixes your problem. My feeling about forms in MVC views is that they should be compact and only cover the markup that contains the actual inputs. This is a change from WebForms where you typically wrap all of your mark up within the form. Use CSS to control layout if you need to have the form elements appear to be intermixed.
This is actually a confirmed bug both in ASP.NET MVC 1.0 with MVC Features library and in ASP.NET MVC 2.0.
RenderAction behaves incorrectly when the request is POST.
I have submitted the bug in ASP.NET Issue Tracker on Codeplex, please vote for it :)
http://aspnet.codeplex.com/WorkItem/View.aspx?WorkItemId=5847

Resources