3

私は次のフォームを持っています:

<form id="MakeDocumentForm" name="MakeDocumentForm" 
      action="Document/GetWordDocument" method="post" 
      enctype="application/json">

    <button type="submit" style="float:right;">Make Word Document</button> 
    <textarea id="hiddenJson" 
              name="hiddenJson" 
              data-bind="text: ko.toJSON(viewModel.selectedDocument)" 
              rows="5" cols="100" 
              style="visibility:hidden;" >
    </textarea>

</form>

属性はknockoutjsですが、data-bindこれは重要ではありません。textareaには、シリアル化されたオブジェクトであるJSONが正しく含まれています。

[HttpPost]
public void GetWordDocument(DocumentModel hiddenJson)
{
   //hiddenJson is not a correctly populated instance of my DocumentModel class
   //any MVC experts know what I am doing wrong?
}

では、MVC 3アプリケーションにフォームPOSTを実行して、逆シリアル化されたクラスを取得するにはどうすればよいですか?

4

1 に答える 1

6

コンテンツタイプをJSONに設定してAJAX経由で投稿する場合、MVC3はコントローラーアクションで適切にバインドできます。

$.ajax({
    url: location.href, 
    type: "POST",
    data: ko.toJSON(viewModel),
    datatype: "json",
    contentType: "application/json charset=utf-8",
    success: function (data) { alert("success"); }, 
    error: function (data) { alert("error"); }
});

ただし、例のように、JSONを含む通常のフォーム投稿を行う場合は、コンテンツタイプがapplication / x-になるため、MVC3がモデルに自動的にバインドしないため、さらに作業を行う必要があります。 www-form-urlencoded。

Steve Sandersonには、送信されたJSONデータをコントローラーアクションで適切にバインドする方法を示す古いサンプルがあります:http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-スタイル/

その要点は、彼が次のような「FromJson」という属性を作成することです。

public class FromJsonAttribute : CustomModelBinderAttribute
{
    private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();

    public override IModelBinder GetBinder()
    {
        return new JsonModelBinder();
    }

    private class JsonModelBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
            if (string.IsNullOrEmpty(stringified))
                return null;
            return serializer.Deserialize(stringified, bindingContext.ModelType);
        }
    }
}

次に、アクションは次のようになります。

    [HttpPost]
    public ActionResult Index([FromJson] IEnumerable<GiftModel> gifts)

また、属性を使用したくない場合は、実際にタイプを登録して、常に特定のモデルバインダーを使用することができます。

次のようなモデルバインダーを作成できます。

public class JsonModelBinder: IModelBinder
{
    private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
        if (string.IsNullOrEmpty(stringified))
            return null;
        return serializer.Deserialize(stringified, bindingContext.ModelType);
    }
}

次に、次のようにglobal.asax.csに登録します。

ModelBinders.Binders.Add(typeof(DocumentModel), new JsonModelBinder());

これで、属性を使用する必要がなくなり、DocumentModelが適切にバインドされます。これは、常にJSON経由でDocumentModelを送信することを意味します。

于 2011-07-23T01:45:51.197 に答える