2011-08-30 6 views
7

クライアント用のJSONソリューションを実装する際に、最近問題が発生しました。アクションパラメータ名がモデルのプロパティ名と一致する場合、バインダはANYプロパティをバインドできません。MVC3 Json Bind Bug?

例:

コントローラ人々

public ActionResult SetEmails(Person emails){ 
    ... 
    return Content(""); 
} 

パラメータ名は、「電子メール」と呼ばれていたので、それは、「電子メール」と呼ばれる人物モデルのプロパティ名と一致..バインダーは失敗しますが、 ..

を理由として任意の表示を与えるものではありません。彼らは人

public class Person { 
    public string Name { get; set; } 
    public List<string> Emails { get; set; } 

    public Person() { 
     Emails = new List<string>(); 
    } 
} 
と呼ばれるモデルを持っていました

これはバグですか、「機能」ですか?

私の質問は、引数名がバインダーとどのように競合するかという点です。名前は、それがjsonデータと照合するスキーマを定義するクラス型であるので重要ではありません。なぜバインダーは引数に名前を付けるか、または引数そのもののクラス型内のプロパティ名と一致する必要がありますか?

+4

あなたは呼び出し元のjsコード、または少なくともあなたが投稿しているJSONを投稿できますか? –

+0

jsonは次のようになります。 {"名前": "John"、 "Emails":["[email protected]"、 "test2 @ test。com] "}} jsonは、私が言ったように、アクション引数名を電子メール(モデルプロパティ名と一致)から変更した後は一致したものにはうまくいきました。なぜこれがうまくいかないのか分かりません。または、少なくとも、ヌルプロパティ値を持つインスタンス化されたクラスの代わりに例外をスローしてください。? – Mike

答えて

2

問題は、辞書にあいまいさがあり、2つの要素が両方とも「電子メール」(ただし、別のケーシングを使用しています)ということです。 DefaultModelBinderはこのあいまいさを解決できません。

2つの解決策:(1)人物モデル全体を返す場合は、最上位要素の名前を「人」に変更します(これは文脈により意味があります)。これはあいまいさを取り除きます(2)電子メールのリストを返すだけの場合は、アクション署名をpublic ActionResult SetEmails(List<Emails> emails)に変更します。

あなたが経験したことは、バグや機能の問題ではなく、デザインの問題です。

+0

私はこの問題を解決した人に切り替えました。名前は必須ではありません。私はレガシーコードを採用していました。最後に、モデルバインダーが失敗する理由は、Action引数名が引数クラスタイプのプロパティ名と一致しているということでした。 なぜこのような曖昧さが発生するのでしょうか? .GetType()。GetProperties()など。jsonに来るものとマッチします。引数クラスの型(スキーマは私が想定しています)がjsonのものとマッチすればいいです。引数nam問題?バインディング中に名前がどのように作用するのでしょうか?それはクラスの種類を指定するのではありません! – Mike

+0

JSONは 'DictionaryValueProvider'を介してバインドされているので、値はキー名によって関連付けられます。同じ名前のキーが2つある場合、辞書は有効ではありません。これが参考になった場合は、回答としてマークしてください。 – counsellorben

+1

これらのキーは、モデルのバインドに使用された引数に指定した名前ではなく、クラスのプロパティから取得する必要があります。 パラメータ名を反復処理するとき、パラメータ名はどのように関連性がありますか? var pi = controller.GetMethod( "action")。GetParameters(); ここでどのようにパラメータの名前を要求するのですか、それがどのポイントでパラメータを取得した結果にどのように影響しますか?そのクラスの型を取得し、そのプロパティを繰り返してデータをバインドします。 同じ名前を持つ2つのプロパティの問題ではありません(無効でコンパイルされません)。 – Mike

0

と答えていますが、プロパティ名を変更することはできません。

JSONオブジェクトをパラメータの変数名でラップします(この場合は「電子メール」です)。だから、これは動作します:

データを:JSON.stringify({Eメール:{名前: "私の名前"、電子メール:[ "[email protected]"、 "[email protected]"]}}) ;

が、これはしません - modelbinderは、代わりにnullを返します:

データ:JSON.stringify({名: "私の名前"、電子メール:[ "[email protected]を"、 " [email protected] "]});

まだ、これはかなり駄目です。しかし、物事はカバーの下で深く働いている、私のWebクライアントが正しく動作するためにコントローラのパラメータ名が何であるかを知る必要はありません。私の言う限りでは、MVCのモデルバインダーのバグです。