【问题标题】:How do you debug an MVC 5 application that uses knockout.js?如何调试使用 knockout.js 的 MVC 5 应用程序?
【发布时间】:2016-08-26 16:49:17
【问题描述】:

我正在阅读 Jamie Munro 所著的“带有 Bootstrap 和 Knockout.js 的 ASP.NET MVC 5”一书。我是一位经验丰富的程序员,但在 MVC 和 Web 开发方面是一名业余爱好者。这是尝试学习如何做到这一点。

在阅读本书时,我在应用程序的某个地方犯了一个错误,所以现在我无法将提交或编辑保存到我的数据库中。而且我不知道如何弄清楚错误是什么。

示例代码仅给出一般错误。了解如何公开内部异常或错误消息会很有帮助。生成此通用错误横幅的代码 sn-p 如下:

self.errorSave = function () {
    $('.body-content').prepend('<div class="alert alert-danger"><strong>Error!</strong> There was an error saving the author.</div>');
}

我有两个问题,一个是具体的,一个是一般的。

具体来说:如何在我的网络浏览器中获得更详细的错误消息?

通用:如何调试 Web 应用程序?当 Visual Studio 不是 Web 应用程序时,我知道如何在它中进行调试,但我无法捕获此错误。我的控制器或模型甚至我的表单中的断点都没有给我任何有用的信息。我还尝试了 Chrome 和 Internet Explorer 中的调试器,但没有找到比“内部服务器错误:500”更有用的方法,这并没有告诉我太多。

本书的代码示例可以在这里找到:https://github.com/oreillymedia/ASP_NET-MVC-5-with-Bootstrap-and-Knockout_js

据我所知,该示例有效。我没有运行它,因为我没有本地 SQL Server,但如果我真的很绝望,我将不得不设置它只是为了并排运行两组代码。比较我的代码并没有指出我的错误。当然,这是一个完整的示例,我的代码只更新了本书的 1/3。

在我的 Action Method 中,第一个检查是 ModelState.IsValid,它返回 false。因此,没有保存。

    public ActionResult Create([Bind(Include = "Id,FirstName,LastName,Biography")] Author author)
    {
        if (ModelState.IsValid)
        {
            db.Authors.Add(author);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(author);
    }

模型绑定似乎无法正常工作。

在表单中,First Name 字段的设置方式如下:

        <div class="form-group">
            @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" }, data_bind = "value: author.firstName" })
                @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
            </div>
        </div>

在模型中,Author.cs:

public class Author
{
    [JsonProperty(PropertyName ="id")]
    public int Id { get; set; }

    [JsonProperty(PropertyName = "firstName")]
    [Display(Name = "First Name")]
    [Required]
    public string FirstName { get; set; }

    [JsonProperty(PropertyName = "lastName")]
    [Display(Name = "Last Name")]
    [Required]
    public string LastName { get; set; }

    [JsonProperty(PropertyName = "biography")]
    public string Biography { get; set; }

    [JsonProperty(PropertyName = "books")]
    public virtual ICollection<Book> Books { get; set; }
}

AuthorFormViewModel.js 看起来像这样:

function AuthorFormViewModel(author) {

var self = this;

//variables to track state during saving
self.saveCompleted = ko.observable(false);
self.sending = ko.observable(false);

self.isCreating = author.id == 0;

//variable to track changes to model
self.author = {
    id: author.id,
    firstName: ko.observable(),
    lastName: ko.observable(),
    biography: ko.observable(),
};

self.validateAndSave = function (form) {
    if (!$(form).valid())
        return false;

    self.sending(true);

    //include anti forgery token
    self.author.__RequestVerificationToken = form[0].value;

    $.ajax({
        url: (self.isCreating) ? 'Create' : 'Edit',
        type: 'post',
        contentType: 'application/x-www-form-urlencoded',
        data: ko.toJS(self.author)
    })
    .success(self.successfulSave)
    .error(self.errorSave)
    .complete(function () { self.sending(false) });
};

self.successfulSave = function () {
    self.saveCompleted(true);

    $('.body-content').prepend('<div class="alert alert-success"><strong>Success!</strong> The author has been saved.</div>');
    setTimeout(function () {
        if ( self.isCreating )
            location.href = './'
        else
            location.href = '../'
    }, 1000);
}

self.errorSave = function () {
    $('.body-content').prepend('<div class="alert alert-danger"><strong>Error!</strong> There was an error saving the author.</div>');
}

}

最后,创建/编辑表单底部的脚本部分尝试以这种方式将所有内容联系在一起:

@section Scripts {
@Scripts.Render("~/bundles/jqueryval", "/Scripts/ViewModels/AuthorFormViewModel.js")
<script>
    var viewModel = new AuthorFormViewModel(@Html.HtmlConvertToJson(Model));
    ko.applyBindings(viewModel);
</script>
}

此外,从@Html.HtmlConvertToJson(Model) 返回的字符串看起来格式正确。这是 Create 尝试返回的内容: + str { “身份证”:0, “名字”:空, “姓氏”:空, “传记”:空, “书”:空 } System.Web.HtmlString

在调试时,似乎 ko.ApplyBindings(viewModel);语句被完全跳过。也许在 viewModel 构造过程中抛出了一个错误(@Html.HtmlConvertToJson(Model) 语句似乎成功)但令人沮丧的是我无法使用该错误,而且我不知道如何获取异常/断点/调用堆栈/东西,以便我可以调查。

【问题讨论】:

  • 将 Visual Studio 断点放在保存数据的操作方法中。检查变量值并查看它们是否与您的预期值匹配。
  • @Shyju 谢谢你的建议。请参阅上面的编辑以获取更多信息。
  • 如果你想在代码中了解,请看How to figure out which key of ModelState has error。或者,如果您的 UI 中有验证辅助方法,它应该在 UI 中显示错误消息
  • @user2316154 听起来您的模型没有绑定,这通常归结为表单字段 name 属性与模型属性不匹配。尝试在浏览器中检查发布数据。是时候看看模型绑定在 MVC 中是如何工作的了。
  • @user2316154,我可以为您提供解决此问题的建议,例如使用 AllErrors 属性。 stackoverflow.com/questions/2996139/…。还请在调试中启用异常设置,它会抛出 unhandle Exception。

标签: asp.net-mvc visual-studio-debugging


【解决方案1】:

我想跟进这个问题。

首先,我要感谢建议我从 vanilla MVC 开始的评论者。那是中肯的建议。在过去的几个月里,我为此度过了很多个晚上,我很高兴地说这是一个更好的方向。

在我获得了一些 MVC 的扎实工作知识并构建了一些小项目来学习它之后,我回到了这个问题并能够解决它。

对于任何发现此问题的人,这里就是错误所在。

在 AuthorFormViewModel 中,我的代码使用 Knockout 将模型数据绑定到表单。

错误就在视图模型的顶部,其中变量设置为可观察的 Knockout 绑定:

self.author = {
    id: author.id,
    firstName: ko.observable(),
    lastName: ko.observable(),
    biography: ko.observable(),
};

空变量!未绑定到从 MVC 模型绑定传入的作者模型。

应该是:

self.author = {
    id: author.id,
    firstName: ko.observable(author.firstName),
    lastName: ko.observable(author.lastName),
    biography: ko.observable(author.biography),
};

具有讽刺意味的是,错误根本不在 MVC 部分,但它确实让我学习了 ASP.NET 和 MVC,对此我很感激。

我认为我从来没有获得过这么多的逻辑来解决这个微不足道的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    • 2014-02-13
    • 2014-05-13
    • 1970-01-01
    • 2015-12-31
    • 2010-11-03
    相关资源
    最近更新 更多