1

Trying to send a string value to Home controller using Ajax. Following Ajax call gives the error (in Google Chrome developer tool): Failed to load resource: the server responded with a status of 404 (Not Found):

$.ajax({
    url: 'Home/TestAction',
    data: "Test data",
    type: 'POST',
    success: function (obj) {
        alert('Suceeded');
    }
});

UPDATE:

After I've tried the url part from all the responses (as of now) to this post, the url turns out to be correct but I'm still getting a warning and an error as shown in the image below. NOTE: The names of the controller and action in the image are different but they are in the same default folder called Controllers in VS2015. I've not created any subfolder etc. Also, this is on development machine Win10 with VS2015 ASP.NET Core 1.1, IIS EXPRESS. Please click on the image to be able to see the message in clear.

UPDATE 2:

To make my question simpler to understand, I've created a test ASP.NET Core app following this official ASP.NET MVC Core tutorial. Please see the error image below.

Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Genre,Price,ReleaseDate,Title")] Movie movie)
{
    if (id != movie.ID)
    {
        return NotFound();
    }

    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(movie);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!MovieExists(movie.ID))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        return RedirectToAction("Index");
    }
    return View(movie);
}

View [..\views\movies\Index.cshtml]. NOTE: I've only added an extra button <button type="button" id="testid" class="Savebtn">Test</button> and the Ajax call at the end.

@model MovieGenreViewModel

@{
    ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
    <p>
        <select asp-for="movieGenre" asp-items="Model.genres">
            <option value="">All</option>
        </select>

        Title: <input type="text" name="SearchString">
        <input type="submit" value="Filter" />
    </p>
</form>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].Price)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.movies[0].Title)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.movies) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                <button type="button" id="testid" class="Savebtn">Test</button>
                <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>
@section scripts
{
    <script>
        $(document).ready(function () {

            $('.Savebtn').click(function () {

                    $.ajax({
                        url: '@Url.Action("Edit", "Movies")',
                        data: "Test data",
                        type: 'POST', //POST if you want to save, GET if you want to fetch data from server
                        success: function (obj) {
                            // here comes your response after calling the server
                            alert('Suceeded');
                        },
                        error: function (obj) {
                            alert('Something happened');
                        }
                    });
            });
        });
    </script>
}

Error [in Google Chrome developer tool]:

enter image description here

6
  • 2
    url: '@Url.Action("TestAction", "Home")', - always use Url.Action() to correctly generate your url's Commented Jan 18, 2017 at 6:42
  • Please show your controller code Commented Jan 18, 2017 at 10:20
  • @StephenMuecke I'm still getting and error. I've added an UPDATE section to my post. Commented Jan 18, 2017 at 16:11
  • @HaithamShaddad I've added an UPDATE 2 section with more details you and others have requested. Commented Jan 18, 2017 at 17:46
  • @nam, Answers do not go in the question and I have rolled back your changes. Feel free to add your own answer if the existing ones do not address the issue. And in future, do not keep editing your question when the original issue has been solved just because you get different errors (you need to ask a new question). And as a side note return RedirectToAction("Index"); in your PST method is pointless - ajax calls never redirect - the whole point of using them is to stay on the same page Commented Jan 18, 2017 at 22:03

3 Answers 3

2

All of the answers posted before seem to be very unflexible and not working, when the JavaScript code is not defined within the razor template engine, which is counter productive when you bundle/minify your cs/js files.

Try adding this to your _Layout.cshtml file inside the header section

<head>
    ...
    <base href="~/"/>
</head>

This sets the base url to your application home. All relative urls will be appended to this base url. This should also work with jQuery requests as the newer versions do respect the base-Tag and hence should work well when your JavaScript code is not rendered within the razor (*.cshtml) templates.

Update

Well...

  1. problem is that your controller action expects a Movie model. You can't send a simple string.
  2. What you posted is an MVC action, it returns a view, no data. You can't use this for ajax, because it will return HTML Code. For Ajax you need Json object.

Your action should look something like

[Route("api/[controller")]
public class MovieController {
    [HttpPost("{id}")]
    public async Task<IActionResult> Edit(int id, [FromBody] Movie movie)
    {
    
    }
}

Note: Usually for RESTful services you use PUT to update/replace a resource and POST to create it. See Relationships between URL and HTTP Methods.

and your jQuery/Ajax request like

// example movie object, this depends on the definition of your model class on the server
var movie = {
    id: 1,
    name: "Back to the Future", 
    genre: "Sci-Fi"
};
$.ajax({
    url: 'api/movies/'+movie.id,
    data: movie,
    type: 'POST',
    success: function (obj) {
        alert('Suceeded');
    }
});
Sign up to request clarification or add additional context in comments.

9 Comments

Url.Action() should always be used, and if the script is in a separate file, then the url can be defined in the main view
@StephenMuecke: That's just workarounds. Splitting the urls into some odd variables in template and use these global variables in the javascript code is just ugly and hard to maintain. @Url.Action is useful when creating links inside your templates. Not so useful when you use ajax/javascript
You might be on your own there :) But each to their own.
@Tseng Still getting error shown in the new UPDATE section of my post.
Nope, you got a different error (HTTP 400, instead of 404 which means Not Found). This one is because validation in the controller failed. Can you post your controller code and the response that is sent (i.e. using Firefox Networkmonitor, hit F12). I suspect its due to the way your data is sent, but can't tell unless I see your controller/action code
|
2

change you url to

   url: '@Url.Action("TestAction", "Home")'

Always use Url.Action helper method to Generates a fully qualified URL to an action method. You can check more detail and overload here

1 Comment

This may not work well for the OP, depending on if the javascript is in it's own *.js file or within the razor template.
2

Is should be (if you in js file):

$.ajax({
    url: '/Home/TestAction', //note this line (You get your url from root this way, not relative like you do)
    data: "Test data",
    type: 'POST',
    success: function (obj) {
        alert('Suceeded');
    }
});

Or like Stephen Muecke said (if your script on View):

$.ajax({
    url: '@Url.Action("TestAction", "Home")', //note this line
    data: "Test data",
    type: 'POST',
    success: function (obj) {
        alert('Suceeded');
    }
});

5 Comments

Same to you btw. Absolute URLs should be avoided and easily break your app, as apps can be installed in virtual folders, which then breaks all absolute or root-related urls. Also @Url razor syntax is unavailable outside of cshtml files
@Tseng i mension it in answer
Yes, but your url is relative. It only works if the application is installed in /. But if you install the application in /MyApp (in IIS or as virtual folder/path/host in nginx), all ajax queries break, because they still connect to /Home/SomeAction instead of /MyApp/Home/SomeAction ;) It's called root-relative links
@Tseng agreed. But let's wait OP. He will clerify his situation
@teovankot Still not working. Please see the new UPDATE section in my post.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.