20

在当前的一个项目中,客户要求以两种方式回答问卷的可能性:以单一形式使用Wizard(一次一个问题)和(一次所有问题)。Listing这两种方式都已经实现。

这些问题是使用 AJAX 根据手册的章节从数据库中加载的(这非常快)。目前最大的章节有230问题(每个都有 4 个 HTML 输入字段 - 输入/文本、选择等)。如果用户选择这样的章节以Listing格式回答,<form>则将包含920要发布到服务器的关于字段。

我正在做一个 AJAX POST 请求,使用 jQuery 的serialize方法传递数据:

data: $("#questions :input").serialize()

这个序列化需要207.143ms完成。我在 Firefox 中使用 Firebug 调试了这个值:

console.profile();
$("#questions :input").serialize();
console.profileEnd();

再次,这是超级快...

当对以下操作方法接收到的数据进行水合时,问题就出现了:

public async Task<ActionResult> ListSaveAsync(IEnumerable<AnswerViewModel> questions)

如您所见,发布的数据是绑定到IEnumerable<AnswerViewModel> questions. AnswerViewModel只有 4 个字段来存储每个答案。

问题是,在单击 Save 按钮后,需要相当长的时间(精确 10 秒)才能在此操作方法上命中断点,也就是说,这 10 秒大概是在模型绑定器中花费的。

需要提及的重要一点是,当从 HTTP POST 实现 ViewModel 集合属性时,我正在使用 Steve Sanderson 的@Html.BeginCollectionItem 助手来提供帮助。查看数据如何进入 ViewModel(键):

在此处输入图像描述

你知道我可以尝试做些什么来优化它吗?

我想到了4个解决方法:

  1. 只保存修改后的问题。为此,我需要在加载列表时将每个答案值存储在数据属性中,并在提交时将其与实际值进行比较,<form>正如这个人在这里建议的那样。

  2. 在客户端创建AnswerViewModelJavaScript 对象并将它们传递给 action 方法。这会减轻 Model Binder 的负担吗?

  3. 滚动我自己的模型绑定器......但我真的不知道它是否会比 ASP.NET MVC 附带的默认模型更快。从我读到的默认模型绑定器做了很多反思来设置值/水合动作的模型参数,这可能是瓶颈。

  4. 使用并枚举发布的数据,通过键获取每个值并手动执行验证,如此FormCollection所示。

你还有什么建议?


更新 1

我选择了选项 3 并实现了一个自定义模型绑定器:AnswerModelBinder : IModelBinder并在该特定操作方法中使用它:

public async Task<ActionResult> ListSaveAsync(
             [ModelBinder(typeof(AnswerModelBinder))]List<AnswerViewModel> questions)

现在10 seconds完成的只需要2 seconds.

  • 看起来默认模型绑定器验证检查 [ ModelState] 对性能有很大影响。

更新 2

我刚刚再次体验到它:将 aList<Guid>作为操作参数并仅59 strings通过$.getJson调用需要大约 3 秒才能在操作方法的第一行遇到断点。更改参数类型以List<string>使整个事情在眨眼之间工作。

一个有趣的事实是,在 action 方法中我这样做了:

List<Guid> userIds = resources.Select(Guid.Parse).ToList();

并将资源List<string>转换为List<Guid>瞬间。

ASP.NET 模型绑定器肯定有一些问题。我只是想知道它是什么...... :)

4

3 回答 3

2

您可以使用 ServiceStack JsonSerializer,它在基准测试结果中非常快,这里是文档 http://mono.servicestack.net/docs/text-serializers/json-serializer ,这里是基准测试 http://mono.servicestack.net/benchmarks /

于 2014-03-21T09:11:16.607 回答
1

这可能不是您正在寻找的答案,但它可能会有所帮助。尝试让控制器方法接受签名中的模型并使用 Ajax.BeginForm(),而不是使用 FormCollection。这将消除对序列化的需要,并允许 MVC 完成它的工作。此外,拥有一个具有问题类型列表的模型可能值得研究。这种方法似乎也消除了对帖子上的值进行迭代的需要,因为它们已经在模型中。

于 2013-05-24T12:26:01.963 回答
0

I haven't tried this but when I use integer indices the binder had no problems in binding to the IEnumerable. Since you are not actually using these Guids I'd replace them with integers. (0,1,2...)

I guess you could do this easily on the page that renders the form or using JS.

于 2014-03-11T10:25:55.150 回答