为什么ASP.NET MVC默认的模型绑定器很慢?做好工作需要很长时间 [英] Why ASP.NET MVC default Model Binder is slow? It's taking a long time to do its work

查看:207
本文介绍了为什么ASP.NET MVC默认的模型绑定器很慢?做好工作需要很长时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



我正在做一个AJAX POST请求,通过jQuery的 serialize 方法:

  data:$(#questions:input)。 serialize()

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

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

再次这是超快...



当使用以下操作方法保持接收到的数据时,问题出在:

  public async任务< ActionResult> ListSaveAsync(IEnumerable< AnswerViewModel>问题)

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



事情是需要相当长的时间(精确的10秒钟),点击保存按钮打到这个动作方法上的一个断点,也就是说,这个10秒钟被用在模型绑定器中。



要提到的是,我使用史蒂夫·桑德森的。


  • 创建 AnswerViewModel 客户端的JavaScript对象,并将它们传递给action方法。这会减轻模型绑定吗?


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


  • 使用 FormCollection ,并枚举通过键获取每个值的已发布数据,并手动执行验证,如这里


  • 你还建议什么?






    更新1



    我选择了3,并实现了一个自定义的模型绑定器: AnswerModelBinder:IModelBinder 并将其用于该特定的操作方法: / p>

      public async任务< ActionResult> ListSaveAsync(
    [ModelBinder(typeof(AnswerModelBinder))]列表< AnswerViewModel>问题)

    现在采取 10秒完成只需 2秒




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



    更新2



    我刚刚经历过一次:有一个 List< Guid> 作为一个动作参数,只通过 $。getJson c $ c> call需要〜3秒钟来触发动作方法第一行的断点。将参数类型更改为列表< string> 使得整个事情都在眨眼之间。



    有趣的事实是在action方法之内我做了这个:

     列表&Guid。 userIds = resources.Select(Guid.Parse).ToList(); 

    ,它会转换资源列表< string> 列表< Guid> 即时。



    肯定有一些bug与ASP.NET模型绑定。我只想知道是什么...:)

    解决方案

    您可以使用ServiceStack JsonSerializer,结果
    这里是文档
    http://mono.servicestack .net / docs / text-serializers / json-serializer
    这里是基准
    http://mono.servicestack.net/benchmarks/


    In a current project the client asked for the possibility of answering a questionnaire in two ways: using a Wizard (one question at a time) and Listing (all questions at once) in a single form. Both ways are already implemented.

    The questions are loaded from the database per Manual's chapter using AJAX (this is super fast). The biggest chapter at the moment has 230 questions (each with 4 HTML input fields - input/text, select, etc). If the user selects such Chapter to answer in the Listing format, the <form> will contain at about 920 fields to be posted to the server.

    I'm doing an AJAX POST request passing the data with jQuery's serialize method:

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

    This serialization takes 207.143ms to complete. I got this value debugging with Firebug in Firefox:

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

    Again this is super fast...

    The problem comes when hydrating the data received on the following action method:

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

    As you see, the posted data is data bound to an IEnumerable<AnswerViewModel> questions. AnswerViewModel has only 4 fields to store each answer.

    The thing is that it takes a considerable amount of time (precisely 10 seconds) after clicking the Save button to hit a breakpoint on this action method, that is, those 10 seconds are being spent in the model binder presumably.

    An important thing to mention is that I'm using Steve Sanderson's @Html.BeginCollectionItem helper to help when materializing the ViewModel collection properties from the HTTP POST. See how the data gets in the ViewModel (Keys):

    Do you know what I can try to do to optimize this?

    I thought about 4 workarounds:

    1. Save back only the modified questions. To do this I'd need to store each answer value in a data-attribute when loading the listing and compare it with the actual value when submitting the <form> as this guy suggests here.

    2. Create AnswerViewModel JavaScript objects on the client side and pass them to the action method. Would this alleviate the Model Binder?

    3. Roll my own model binder... but I really don't know if it would be faster than the default one that comes with ASP.NET MVC. From what I've read the default model binder does a lot of reflection to set the values/hydrate the action's model parameter and this could be the bottleneck.

    4. Use FormCollection and enumerate through the posted data getting each value by key and performing validation manually as shown here.

    What else do you suggest?


    Update 1

    I went with option 3 and implemented a custom Model Binder: AnswerModelBinder : IModelBinder and used it in that specific action method:

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

    Now what took 10 seconds to complete takes only 2 seconds.

    • Looks like the default model binder validation checks [ ModelState ] has a big impact on performance.

    Update 2

    I just experienced it once again: having a List<Guid> as an action parameter and passing only 59 strings through a $.getJson call was taking ~3 seconds to hit a breakpoint in the 1st line of the action method. Changing the parameter type to List<string> made the whole thingy work in the blink of an eye.

    An interesting fact is that inside the action method I did this:

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

    and it transforms the resources List<string> to a List<Guid> instantaneously.

    For sure there's something buggy with ASP.NET model binder. I just would like to know what it is... :)

    解决方案

    You can use ServiceStack JsonSerializer which is pretty fast in benchmark results here is documentation http://mono.servicestack.net/docs/text-serializers/json-serializer and here is the benchmarks http://mono.servicestack.net/benchmarks/

    这篇关于为什么ASP.NET MVC默认的模型绑定器很慢?做好工作需要很长时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆