2011-07-22 3 views
3

私は次のような形式がありますMVC 3アプリケーションへのフォームPOSTを行い、非直列化クラスを取得する方法は?

<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> 

data-bind属性がknockoutjsである - しかし、これは重要ではありませんが、テキストエリアが正しくシリアライズされたオブジェクトである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を行い、非直列化クラスを取得するにはどうすればよいですか?

答えて

6

コンテンツタイプをJSONに設定してAJAX経由で投稿している場合、MVC 3はコントローラアクションで正しくバインドできます。あなたの例のように、あなたはJSONを含み、通常のフォームのポストをしたい場合は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"); } 
}); 

はしかし、あなたはコンテンツとして、いくつかのより多くの作業を行う必要がありますtypeはapplication/x-www-form-urlencodedになります。 http://blog.stevensanderson.com/2010/07/12/editing-a-variable-length-list-knockout-style/

それの要旨は、彼がどのように見える「FromJson」という属性を作成することです::

スティーブサンダーソンは、ここではあなたのコントローラのアクションに適切に拘束されることにJSONデータを提出したばかり実証古いサンプルを持っています

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を送信することを常に意味します。

+0

すごくお礼ありがとうございます!フォームポストの結果は、ユーザーがポップアップを取得して直接開くことができるようにするためのワードドキュメントであるため、私はどのようにajaxを使用できるのか分かりません。これは正常なHTMLフォームの投稿としてすべてのブラウザで正常に動作します。しかし、あなたの他のアイデアは良いと思う。 – pilavdzice

+0

ありがとうライアン。素晴らしい解決策。もう一度あなたは私を束縛から救い出されました:-) –