0

Here's my code (question found below):

VIEW

// This function is called by another function when radioButtonGroup.change().
var requestValues = function (form) {
    var option = form.find("input:radio:checked").attr("value");

    // This seemingly shows the correct url for the action method desired.
    alert("Form Action: " + form[0].action + "\nForm Method: " + form[0].method);

    if (form.valid()) {
        $.ajax({
            url: form[0].action,
            type: form[0].method,
            data: option,
            success: function (result) {
                alert("Had success.");
                $('#createForm').replaceWith(result);
            },
            error: function (xhr) {
                alert("An error occurred: " + xhr.status + " " + xhr.statusText);
            }
        });
    }
    return false;
}

...(other code here)...

@using (Html.BeginForm("CreateForm", "MyController", FormMethod.Post, 
                        new { @id = "optionForm" }))
{
    <div id="options">
        @foreach (MyOption op in Model.GetOptions()) {
            <div class="editor-field">
            @Html.RadioButton("formOption", op.OptionType, false, 
                new { @id = op.ID, @title = @op.Description })
            <label for="@op.ID">@op.Name</label>
            </div>
        }
    </div>
    <input type="submit" value="Select" style="display:none;" />
}

CONTROLLER

[HttpPost]
public PartialViewResult CreateForm(MyOptionType formOption) {
    MyViewModel model = new MyViewModel();
    model.ApplyOptionValues(formOption);
    return PartialView("_CreateForm", model);
}

REGISTER ROUTES

// Default
routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
     new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

My issue is that when I click a radio button, the AJAX request executes but I get a "404 Not Found" error (even though the alert in the jQuery function seems to show the appropriate url). I spent all day yesterday on this, and I cannot figure out what the heck is wrong. I'm running ASP.NET MVC 3 app on IIS Express, and I'm not using Areas (that I know of anyway). Anyone have any suggestions on how to fix this? Thanks.

EDIT

The alert box shows the following message:

Form Action: https://localhost:44300/MyController/CreateForm

Form Method: post

EDIT

Here is an entire test view and test controller that recreates the error:

VIEW

<h2>TestAction</h2>

<script type="text/javascript">
    $(document).ready(function () {
        $("#optionForm input[name='radioOption']").change(function () {
            requestValues($(this).closest("form"));
        });

        var requestValues = function (form) {
            var option = form.find("input:radio:checked").attr("value");

            alert("Form Action: " + form[0].action + "\nForm Method: " + form[0].method);

            if (form.valid()) {
                $.ajax({
                    url: form[0].action,
                    type: form[0].method,
                    data: option,
                    success: function (result) {
                        alert("AJAX success.");
                        //$('#createForm').replaceWith(result);
                    },
                    error: function (xhr) {
                        alert("An error occurred: " + xhr.status + " " + xhr.statusText);
                    }
                });
            }
            return false;
        }
    });
</script>

@using (Html.BeginForm("CreateForm", "Test", FormMethod.Post, new { @id = "optionForm" })) {
    @Html.RadioButton("radioOption", "value1", false, new { @id = "radioButton1" })
    <label for="radioButton1">Radio Button 1</label>
    @Html.RadioButton("radioOption", "value2", false, new { @id = "radioButton2" })
    <label for="radioButton2">Radio Button 2</label>
    @Html.RadioButton("radioOption", "value3", false, new { @id = "radioButton3" })
    <label for="radioButton3">Radio Button 3</label>

    <input type="submit" value="Select" style="display:none;" />
}

<div id="createForm"></div>

CONTROLLER

public class TestController : Controller {
    public ActionResult TestAction() {
        return View();
    }

    [HttpPost]
    public ActionResult CreateForm(string option) {
        return View("TestAction");
    }
}
neizan
  • 2,291
  • 2
  • 37
  • 52
  • Suggest you use a tool like Fiddler, or the Network tool in Chrome (Ctrl Shift I) - the 404 will be highlighted in Red and you can see what the offending URL is. – StuartLC Aug 14 '12 at 08:12
  • Is MyController the real name of the controller? Can you give us a bit more detail to attempt reproducing your problem? – Simon Whitehead Aug 14 '12 at 08:13
  • Can you post what is displayed in the alert? – nemesv Aug 14 '12 at 08:19
  • Are you sure using https and port 44300? I guess your iis express misconfigured. – sigurd Aug 14 '12 at 08:37
  • @nemesv, I've added the alert message in an edit. – neizan Aug 14 '12 at 08:38
  • @Simon Whitehead, MyController is not the real name, I've cleaned up naming to make things shorter and (maybe) easier to follow. I'll see what I can do to get you more detailed code to reproduce the error. – neizan Aug 14 '12 at 08:40
  • Have you got a jQuery default that's forcing it to use GET for ajax requests? Use Fiddler or Chrome Developer tools/firebug to check. Just because your form is set to POST doesn't mean ajax is. – Tim Croydon Aug 14 '12 at 08:41
  • @sigurd, I'm pretty sure the 'https' and the port are correct. All other controller/action combinations have worked up until now, when, for the first time, I've introduced the AJAX aspect. – neizan Aug 14 '12 at 08:41
  • @Tim Croydon, how do I check whether I have a jQuery default forcing a GET? The odd thing is that I tried using a GET instead of a POST to see what happens, and then it gave me a 500 error instead of 404. – neizan Aug 14 '12 at 08:43
  • I didn't notice you were using the 'type' parameter. If you're using Chrome, press CTRL-SHIFT-I to bring up the dev tools and look at the network tab. You'll see the ajax request including the actual url, post/get and the send/return data. A 500 error sounds very much like it's now a problem in your code - try putting a breakpoint in your controller action to see or look at the web response. – Tim Croydon Aug 14 '12 at 08:48
  • My answer was more of a comment: You realise your radiobuttons are posting to the same URL your form is yes? MVC won't bind a string properly unless you tell it to in your post. – Simon Whitehead Aug 14 '12 at 09:10
  • Ok, I'm back...I posted some additional test code that recreates the error. Hopefully this will help anyone who wants to try to recreate it on his end. – neizan Aug 14 '12 at 09:27
  • @Tim Croydon, I had put a breakpoint in the controller and it didn't get hit. – neizan Aug 14 '12 at 09:32

1 Answers1

5
@using (Html.BeginForm("CreateForm", "MyController", FormMethod.Post, new { id = "optionForm" }))

should be:

@using (Html.BeginForm("CreateForm", "My", FormMethod.Post, new { id = "optionForm" }))

Remember that in ASP.NET MVC helpers you should not pass the Controller suffix. It is assumed.

So the correct url should be:

https://localhost:44300/My/CreateForm

and not:

https://localhost:44300/MyController/CreateForm

where you obviously have the MyController class:

public class MyController: Controller
{
    public ActionResult CreateForm(MyOptionType formOption)
    {
        ...
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • The 'MyController' example name was a poor choice. The real code omitted the 'Controller' part as you mentioned. I posted new test code that maybe shows it better. I apologize for the confusion. – neizan Aug 14 '12 at 09:35
  • `data: option` should be `data: { option: option }`. Also where do you see this 404 error? In FireBug when looking at the AJAX request? Also you seem to be using HTTPS. Are you sure this is properly configured in IIS Express? on't forget that the port for HTTPS is different in IIS Express with the port used to serve HTTP. – Darin Dimitrov Aug 14 '12 at 09:37
  • I'll try changing the data, but I did already remove the data from teh ajax code and remove the parameter from the action method being called, and the same error was generated. Now, regarding the 404 error, I see it in the alert box from the `error: ...` portion of the ajax code. Https...I thought I was set up to use it, because all of my other controller/action combinations work on https, and I haven't had any problems until trying to use ajax. – neizan Aug 14 '12 at 09:45
  • I changed the data parameter of the ajax code and I still get the same error. – neizan Aug 14 '12 at 09:48
  • What happens if you type the GET action url directly in your browser: `https://localhost:44300/Test/TestAction`? Does it get served? – Darin Dimitrov Aug 14 '12 at 09:50
  • 1
    Ok, this is odd. I just change the `HttpPost` attr on the controller action to `HttpGet` and I get the success alert box (from my test code above)...I no longer get the error. However, I did not change the HTML form's `FormMethod`, so it was still `FormMethod.Post`. What is going on? Oh, and by the way, the `...Test/TestAction` always worked. It was the `...Test/CreateForm` that was giving the 404 error, and as I mentioned, both now work despite the POST/GET inconsistency. – neizan Aug 14 '12 at 10:01
  • I just changed the `FormMethod` to `Get` (leaving the action attr as `HttpGet`), and it works the same as `FormMethod.Post`. Tim Croydon, in a comment above, mentioned that a jQuery default could be forcing a GET...with my new findings, I may need to investigate that further, but how? – neizan Aug 14 '12 at 10:10
  • 1
    You can use (without the double quotes) "type: 'POST'" to force the ajax request to be a POST. jQuery defaults to GET, unless you have a global setting (see http://api.jquery.com/jQuery.ajaxSetup/). Specifying in the request should override the globals/defaults though. Think the first thing you need to do is confirm whether you're actually GETting/POSTing using the techniques mentioned above. You can then worry about any model-binding errors as a separate issue! – Tim Croydon Aug 14 '12 at 15:49
  • @Tim Croydon, thanks for following up. In my code above, however, I check (via an alert) which form method is being used, and it always spits out what I've specified in the `Html.BeginForm` statement. I eventually just sort of avoided the problem by using the `FormMethod.Get` which works perfectly. However, I'm running into a similar problem with a plain old `Html.BeginForm`, again using `POST`. Seems this question had less to do with AJAX than I initially thought. I've posted a new question [here](http://stackoverflow.com/questions/12034533/asp-net-mvc-3-httppost-action-method-not-found). – neizan Aug 20 '12 at 08:41
  • @Darin Dimitrov, although this answer didn't solve my problem, your follow-up comments got me on the path to getting closer to finding the root of my problem, so I'll go ahead and accept this. Note my new question (similar to this one, but more concise) [here](http://stackoverflow.com/questions/12034533/asp-net-mvc-3-httppost-action-method-not-found). Thanks! – neizan Aug 20 '12 at 08:44