【问题标题】:ASP.NET MVC Core posting just a string to controller via Ajax PostASP.NET MVC Core 通过 Ajax Post 向控制器发布一个字符串
【发布时间】:2017-01-18 06:35:23
【问题描述】:

尝试使用 Ajax 向 Home 控制器发送字符串值。以下 Ajax 调用给出了错误(在 Google Chrome 开发者工具中):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');
    }
});

更新

之后我已经尝试了这篇文章的所有回复中的 url 部分(截至目前),结果证明 url 是正确的,但我仍然得到一个 warning 和一个error 如下图所示。 注意:图片中的控制器名称和动作名称不同,但它们在 VS2015 中名为 Controllers 的同一个默认文件夹中。我没有创建任何子文件夹等。另外,这是在开发机器Win10 with VS2015 ASP.NET Core 1.1, IIS EXPRESS 上。请点击图片以清晰地看到消息。

更新 2

为了让我的问题更容易理解,我在official ASP.NET MVC Core tutorial 之后创建了一个测试 ASP.NET Core 应用程序。请看下面的错误图片。

控制器

[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);
}

查看 [..\views\movies\Index.cshtml]。注意:我只添加了一个额外的按钮 <button type="button" id="testid" class="Savebtn">Test</button> 和最后的 Ajax 调用。

@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>
}

错误 [在 Google Chrome 开发者工具中]

【问题讨论】:

  • url: '@Url.Action("TestAction", "Home")', - 始终使用Url.Action() 正确生成您的网址
  • 请出示您的控制器代码
  • @StephenMuecke 我仍然遇到错误。我在帖子中添加了 UPDATE 部分。
  • @HaithamShaddad 我添加了一个 UPDATE 2 部分,其中包含您和其他人要求的更多详细信息。
  • @nam,问题中没有答案,我已经回滚了您的更改。如果现有答案不能解决问题,请随意添加您自己的答案。将来,当原始问题已解决时,不要仅仅因为您遇到不同的错误而继续编辑您的问题(您需要提出一个新问题)。作为旁注return RedirectToAction("Index"); 在您的 PST 方法中毫无意义 - ajax 调用 never 重定向 - 使用它们的全部意义在于保持在同一页面上

标签: ajax visual-studio-2015 asp.net-core asp.net-core-mvc


【解决方案1】:

当 JavaScript 代码未在 razor 模板引擎中定义时,之前发布的所有答案似乎都非常不灵活且不起作用,这在您捆绑/缩小您的 cs/js 文件时会适得其反。

尝试将此添加到标题部分内的 _Layout.cshtml 文件中

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

这会将基本 url 设置为您的应用程序主页。所有相对 url 都将附加到此基本 url。这也应该适用于 jQuery 请求,因为较新的版本确实尊重 base-Tag,因此当您的 JavaScript 代码未在 razor (*.cshtml) 模板中呈现时应该可以正常工作。

更新

嗯……

  1. 问题是您的控制器动作需要一个电影模型。您不能发送简单的字符串。
  2. 您发布的是一个 MVC 操作,它返回一个视图,没有数据。您不能将它用于 ajax,因为它会返回 HTML 代码。对于 Ajax,您需要 Json 对象。

您的操作应该类似于

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

注意:通常对于 RESTful 服务,您使用 PUT 更新/替换资源并使用 POST 创建它。见Relationships between URL and HTTP Methods

和你的 jQuery/Ajax 请求一样

// 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');
    }
});

【讨论】:

  • Url.Action() 应始终使用,如果脚本在单独的文件中,则可以在主视图中定义 url
  • @StephenMuecke:这只是解决方法。将 url 拆分为模板中的一些奇怪变量并在 javascript 代码中使用这些全局变量是丑陋且难以维护的。 @Url.Action 在模板中创建链接时很有用。使用 ajax/javascript 时没那么有用
  • 你可能在那儿独自一人:) 但每个人都有自己的。
  • @Tseng 我的帖子的新更新部分仍然显示错误。
  • 不,您遇到了不同的错误(HTTP 400,而不是 404,表示未找到)。这是因为控制器中的验证失败。您能否发布您的控制器代码和发送的响应(即使用 Firefox Networkmonitor,按 F12)。我怀疑这是由于您的数据发送方式造成的,但除非我看到您的控制器/操作代码,否则无法判断
【解决方案2】:

把你的网址改成

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

始终使用 Url.Action 辅助方法来生成操作方法的完全限定 URL。您可以查看更多详细信息并重载here

【讨论】:

  • 这可能不适用于 OP,具体取决于 javascript 是在它自己的 *.js 文件中还是在 razor 模板中。
【解决方案3】:

应该是(如果你在 js 文件中):

$.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');
    }
});

或者像 Stephen Muecke 所说的(如果你的脚本在 View 上):

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

【讨论】:

  • 顺便说一句。应避免使用绝对 URL 并轻松破坏您的应用程序,因为应用程序可以安装在虚拟文件夹中,然后会破坏所有绝对 URL 或与根相关的 URL。此外,@Url razor 语法在 cshtml 文件之外不可用
  • @Tseng 我在回答中提到它
  • 是的,但您的网址是相对的。仅当应用程序安装在 / 中时它才有效。但是,如果您将应用程序安装在/MyApp 中(在 IIS 中或作为 nginx 中的虚拟文件夹/路径/主机),所有 ajax 查询都会中断,因为它们仍然连接到 /Home/SomeAction 而不是 /MyApp/Home/SomeAction ;) 它被称为 root-relative链接
  • @Tseng 同意了。但是让我们等待OP。他会澄清他的处境
  • @teovankot 仍然无法正常工作。请在我的帖子中查看新的更新部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-12
  • 2019-06-21
  • 1970-01-01
  • 2012-05-10
  • 2016-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多