我有一个创建视图和一个编辑视图,几乎相同。它们都包含一个级联下拉列表。第二个列表的值是正在创建或编辑的数据的一部分。第一个下拉列表只是第二个列表中值的过滤器。
两个视图都使用相同的脚本,该脚本在第一个下拉列表中附加了更改事件的处理程序。处理程序对控制器中的方法进行发布。
当我运行创建视图并更改第一个下拉列表时,它工作正常。第二个列表已更新。当我在编辑视图中尝试时,我收到 500 内部服务器错误。
我看过Firebug。我在处理程序中放了一个中断。选择时在这两种情况下都会调用它。发送的数据看起来是一样的( $(this).serialize() 看起来一样)。
Firebug 控制台显示:所需的防伪表单字段“__RequestVerificationToken”不存在。我没有看到我需要一个调用此方法,但当然还有其他方法(操作)确实需要一个。
不过,我在昨天之前从未使用过 Firebug,所以如果有人知道如何使用,可能还有很多东西可以检查。(总的来说,我对 MVC 和 Web 应用程序完全陌生。)
我的控制器方法也有中断。仅在从创建视图调用时会被击中。
无奈之下,我尝试将调用类型更改为 GET 而不是 POST。这导致调用了一个具有不同名称的控制器方法(HttpGet EDIT),我觉得至少可以说令人不安。
我感觉找不到我正在调用的方法(在编辑中)。相反,尝试使用其他方法(我不知道是哪一种),并且该方法需要防伪令牌。
编辑: 一阵新鲜空气,我意识到我当然知道调用哪个动作:这是 HttpPost Edit 动作(需要防伪令牌)。这当然是正常的表单提交操作。在调试器中快速运行证实了这一点。这个调用由于手头的原因而失败的事实是清楚的。但是为什么这个动作会被调用呢?
更新: Firebug 控制台指示正在调用不同的操作。在 Create 案例中,它是 .../_an_alphanumeric_literal_/Order/PopulateAvtalDDL,这正是我想要的。在 Edit 情况下,它是 .../_an_alphanumeric_literal_/Order/ Edit /PopulateAvtalDDL。这是路由问题吗?如果是这样,我还是不明白。两个调用都是从同一个脚本发出的,我只设置了一个路由(基本上是 MVC 4 的默认路由):
routes.MapRoute(
name: "Default",
url: "_an_alphanumeric_literal_/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
更新:
我终于找到了一些相关信息:AJAX 请求中的相对 URL。那就是路由问题。如果我将我的脚本 URL 从相对PopulateAvtalDDL
更改为绝对/_an_alphanumeric_literal_/Order/PopulateAvtalDDL
,则它适用于两个视图。引用链接中的答案表明路径相对于浏览器中的当前 URL。在我的情况下是http://localhost:51852/_an_alphanumeric_literal_/Order/Edit/6?markedOrderId=0
and http://localhost:51852/_an_alphanumeric_literal_/Order/Create?markedOrderId=0
。当构建相对 URL 时,最后一段被替换。在 Create 案例中是Create,但在 Edit 案例中它是6(已编辑数据的 ID)。我明白发生了什么!
然后我的解决方案:
在过滤器 DDL 周围添加一个 div(在两个视图中)设置 URL: <div id="kundDDL" data-url="@Url.Action("PopulateAvtalDDL", "Order")">
。然后在脚本中访问那个 URL url: $('#kundDDL').data('url')
。
这是创建视图的代码:
@model AssetMgmt.Models.OrderEditVM
@using AssetMgmt.Models;
@{
ViewBag.Title = MsgString.LblCreateNew + " order";
}
<h2>@ViewBag.Title</h2>
@using (Html.BeginForm(null, null, FormMethod.Post))
{
@Html.ValidationSummary(true)
@Html.AntiForgeryToken()
@Html.HiddenFor(m => m.MarkedOrderId)
<fieldset>
<legend>Filter</legend>
<div class="editor-label">
@Html.LabelFor(m => m.KundId)
</div>
<div class="dropdownlist">
@Html.DropDownListFor(m => m.KundId, Model.KundDropDown, string.Empty)
</div>
<div class="dropdown-validation-error">
@Html.ValidationMessageFor(model => model.KundId)
</div>
</fieldset>
<fieldset>
<legend>Orderdata</legend>
<div id="avtalDDL">
@Html.Partial("_AvtalDDL")
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Ordernummer)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Ordernummer)
@Html.ValidationMessageFor(model => model.Ordernummer)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Beställare)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Beställare)
@Html.ValidationMessageFor(model => model.Beställare)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Orderdatum)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Orderdatum)
@Html.ValidationMessageFor(model => model.Orderdatum)
</div>
<p>
<input type="submit" value="@MsgString.LblSave" />
</p>
</fieldset>
}
<div>
@Html.ActionLink(MsgString.LblBack, "Index", new { markedOrderId = Model.MarkedOrderId })
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript" src="~/Scripts/jquery.maskedinput-1.3.1.min.js"></script>
<script type="text/javascript" src="~/Scripts/assetMgmtMasks.js"></script>
<script src="~/Scripts/assetMgmtOrderPopulateDDL.js" type="text/javascript"></script>
}
这是编辑视图:
@model AssetMgmt.Models.OrderEditVM
@using AssetMgmt.Models;
@{
ViewBag.Title = MsgString.LblEdit + " order";
}
<h2>@ViewBag.Title</h2>
@using (Html.BeginForm(null, null, FormMethod.Post))
{
@Html.ValidationSummary(true)
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.OrderId)
@Html.HiddenFor(model => model.Timestamp)
@Html.HiddenFor(model => model.MarkedOrderId)
<fieldset>
<legend>Filter</legend>
<div class="editor-label">
@Html.LabelFor(m => m.KundId)
</div>
<div class="dropdownlist">
@Html.DropDownListFor(m => m.KundId, Model.KundDropDown, string.Empty)
</div>
<div class="dropdown-validation-error">
@Html.ValidationMessageFor(model => model.KundId)
</div>
</fieldset>
<fieldset>
<legend>Orderdata</legend>
<div id="avtalDDL">
@Html.Partial("_AvtalDDL")
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Ordernummer)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Ordernummer)
@Html.ValidationMessageFor(model => model.Ordernummer)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Beställare)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Beställare)
@Html.ValidationMessageFor(model => model.Beställare)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Orderdatum)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Orderdatum)
@Html.ValidationMessageFor(model => model.Orderdatum)
</div>
<p>
<input type="submit" value="@MsgString.LblSave" />
</p>
</fieldset>
}
<div>
@Html.ActionLink(MsgString.LblBack, "Index", new { markedOrderId = Model.MarkedOrderId })
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript" src="~/Scripts/jquery.maskedinput-1.3.1.min.js"></script>
<script type="text/javascript" src="~/Scripts/assetMgmtMasks.js"></script>
<script src="~/Scripts/assetMgmtOrderPopulateDDL.js" type="text/javascript"></script>
}
剧本:
$(document).ready(function () {
//Kund select
$('#KundId').change(function () {
$.ajax({
url: 'PopulateAvtalDDL',
type: 'post',
data: $(this).serialize(),
success: function (result) {
$('#avtalDDL').html(result);
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(xhr.statusText);
alert(thrownError);
}
});
return false;
});
});
控制器方法的签名:
[HttpPost]
public PartialViewResult PopulateAvtalDDL(int kundId = 0)