web-dev-qa-db-ja.com

ASP.NetMVCポストバックとモデル

これは主にこの問題のコメントのフォローアップですが、コメントするのに十分な評判がありません...

ASP.Net MVCはラベル値をコントローラーにポストバックします

単純なモデルがあるとしましょう:

public class SimpleClass
{
    public String Label { get; set; }
    public String FirstName { get; set; }
}

ラベルはユーザー/クライアントに基づいて変更されるため、DataAttributeにすることはできません。ポストバック処理の問題が発生した場合は、ページ全体を再描画する必要があります。これが前の投稿の問題の核心です。受け入れられている解決策は、これを行うことです。

@Html.DisplayTextFor(model => model.Label)
@Html.HiddenFor(model => model.Label)
@Html.EditorFor(model => model.FirstName)

それが機能するという点でそれは理にかなっています。しかし、私たちのモデルははるかに複雑で広範囲です。この方法では、非常に汚い解決策のように見える大量の非表示フィールドが生成されます。

これは私にJPのコメントをもたらします:

ASP.Net MVCはラベル値をコントローラーにポストバックします

解決策は、モデルをリロードすることです。ただし、これは単なるリロードではなく、クライアント側のデータ変更を保持する必要があるため、マージでもあります。

default: SimpleClass { Label="TheLabel", FirstName="Rob"}
postedback: SimpleClass { Label="", FirstName="Steve" }
we want: SimpleClass { Label="TheLabel", "FirstName="Steve" }

私の質問は、MVCには、正しくマージされるようにポストバックされたフィールドを知る良い方法があるのでしょうか?空白のプロパティではなく、ポストバックフィールドのみをマージする必要があります。

それとも、ポストバック全体を単にajax化して、フォームを送信しない方がよいでしょうか?これにより、送信時のすべてのモデルの再読み込みの問題が回避されます。

更新

パブロの功績を認めるために、私は彼の解決策を受け入れました。彼の解決策の私の簡単な例を見るには、以下の回答のRobertHarveyのコメントを確認してください。

ASP.Net MVCポストバックとモデル

10
Rob

ここでの主な問題は、WebFormsのPostBackの概念をMVCに適合させようとすることです。物事が自動的に状態を保持するステートフルポストバックのようなものはありません。

ビューにバインドされているViewModelと、ビューによってコントローラーに投稿されているViewModelのみがあります。それらは必ずしも同じタイプである必要はありません。つまり、コントローラーは、ユーザーが実際に変更できるデータのみを受信する必要があります。初期のViewModelの一部であるが、読み取り専用である多くのプロパティを持つ大きなオブジェクトは受信しないでください。

ラベルは通常、読み取り専用のテキストを表し、編集可能なフォーム要素ではありません。そのため、非表示フィールドを使用する必要があるのはそのためです。

はい、場合によっては、コントローラーに元のデータを再読み込みし、投稿した新しいデータと同期する必要があることを意味しますが、これは必ずしも悪いことではありません。ユーザーが手動で編集できないビューに読み取り専用データをバインドする場合、後で投稿に返されるデータを実際に信頼するべきではありません。あなたのhtmlがそれを読み取り専用にしようとするかもしれないからといって、私があなたの知らないうちに投稿を操作して最終的にあなたの「読み取り専用」データを変更できないという意味ではありません。

あなたが言及した2番目の質問を読みましたが、その外観から、彼の主な問題は、同じViewModelを再利用しようとしたため、すべてのデータが欠落し、モデルが無効であったことでした。これに対する解決策は確かに非常に単純で、必要なものだけを新しいViewModelタイプとして投稿し、残りはコントローラーに任せます。

6
Pablo Romeo

[OPから移動]

これは、パブロが疑問に思っている人たちに提案していることだと思います。この問題を解決するのに良いパターンのようです。

モデル:

    public class SimpleClass : SimpleClassPostBack
    {
        public String Label { get; set; }

        public SimpleClass()
        {
            // simulate default loading
            Label = "My Label";
            FirstName = "Rob";
        }

    }

    // contains only editable by the user fields
    public class SimpleClassPostBack
    {
        public String FirstName { get; set; }
    }

コントローラのアクション:

    [HttpGet]
    public ActionResult SimpleClassExample3()
    {
        SimpleClass simpleClass = new SimpleClass();
        return View(simpleClass);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult SimpleClassExample3(SimpleClassPostBack postBackSimpleClass)
    {
        Boolean errorOccurred = true;

        if (!errorOccurred)
        {
            // do whatever success action is necessary
        }

        // redraw the page, an error occurred

        // reload the original model
        SimpleClass simpleClass = new SimpleClass();

        // move the posted back data into the model
        // can use fancy reflection to automate this
        simpleClass.FirstName = postBackSimpleClass.FirstName;

        // bind the view
        return View(simpleClass);
    }

見る:

@model SimpleClass

@{
    ViewBag.Title = "Simple Class Example3";
}

<h2>Simple Class Example3</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <label for="FirstName">@Html.DisplayFor(m => m.Label)</label>
    @Html.EditorFor(m => m.FirstName)

    <br/>

    <button>Submit</button>

}
5
Robert Harvey

クライアントからサーバーに送信する必要があるのは、サーバーがそれ自体で「把握」できないデータのみです。ユーザーが最初にそのビューに移動したときにサーバーがラベルを認識している場合、ユーザーがラベルを変更できない場合、サーバーはビューを再ロードするときにラベルが何であるかを知ることができます。

非表示フィールドを使用して、データベースオブジェクトを識別します。したがって、SimpleClassには、非表示の入力で使用するIdのようなものが含まれているはずです。 EditorForにはFirstNameを使用します。フォームが投稿されたら、送信されたIdを使用してデータベースから正しいSimpleClassを見つけ、投稿された値でそのFirstNameプロパティを変更します。 Labelプロパティはnullになります。これは、保存する必要がないので問題ありません。投稿に問題があり、同じビューを以前と同じように送り返したい場合は、ユーザーが初めてビューにアクセスしたときと同じ方法でLabelを再入力する必要があります。 IdプロパティとFirstNameプロパティの値は、モデルの状態とともにビューに自動的に返送されます。

要約すれば:

  • 何かを識別するために必要なデータと、ユーザーがそのビューで編集できるもののみを投稿してください。
  • クライアントがあなたに有効なものを送ることを信用しないでください。ユーザーは、非表示フィールドラベルの値を任意に変更できます。
2
Maetis