0

次のエンティティ モデルがあります。

public class AssetLabel
{
    public string QRCode { get; set; }
    public string asset { get; set; }
    public virtual IEnumerable<Conversation> Conversations { get; set; }
}

public class Conversation
{
    public int ID { get; set; }
    public virtual AssetLabel AssetLabel{ get; set; }
    public string FinderName { get; set; }
    public string FinderMobile { get; set; } 
    public string FinderEmail  { get; set; }
    public  ConversationStatus Status{ get; set; }

    public IEnumerable<ConversationMessage> Messages { get; set; }
}

public class ConversationMessage
{
    public int ID { get; set; }
    public DateTime MessageDateTime { get; set; }
    public bool IsFinderMessage { get; set; }
    public virtual Conversation Conversation { get; set; }
}

public enum ConversationStatus { open, closed };

public class FinderViewModel : Conversation
{/*used in Controllers->Found*/


}

私の MVC アプリケーションはQRCode、POST 要求でプロンプトを表示します。AssetLabel次に、このコードがデータベースに存在し、他のサーバー側のロジックが満たされていることを検証します。次に、ユーザーの連絡先の詳細を要求して、新しい Conversationレコードを作成する必要があります。現在、コードをキャプチャする最初のフォームを返すコントローラー アクションへの GET があります。これが有効な場合は、新しい を作成し 、 に のオブジェクトをFinderViewModel入力し、ビューを返して vm を消費し、 、 、 のフィールドを表示します。私の問題は、 が の一部としてビューに渡されており、 ;からフィールドを表示できることです。グラフ化されたオブジェクトはPOST で返されません。私は私が変更できることを知っていますAssetLabelQRCodeNameMobileEmailAssetLabelFinderViewModelAssetLabelAssetLabelFinderViewModelConversation1 つのプロパティとして取得し、フォームの非表示フィールドになる可能性のある別のプロパティとして設定し、2 番目のフォームの処理の一部としてQRCodeを再検索しますが、これを確認するAssetLabelのは大変な作業のように感じます2 番目のフォームを作成するポイントに到達するために、既に一度検証したためです (これが、PHP MVC フレームワークから離れようとしている理由です)。

最初の質問はどのように?、2 番目の質問は、この設計パターンへのアプローチが間違っているかどうかです。複数のフォームを介してデータを永続化するための、より .NETty な方法はありますか? 私の学習のこの時点では、情報をCookieに保存したり、ajaxを使用したりしたくありません。

参考までに、第 1 フォーム POST、第 2 ビュー、および第 2 フォーム POST の残りのコードを以下に示します (無関係なロジックを削除するために簡略化しています)。

public class FoundController : Controller
{
    private ApplicationDbContext db = new ApplicationDbContext();

    // GET: Found
    public ActionResult Index()
    {
        AssetLabel lbl = new AssetLabel();
        return View(lbl);
    }

    [HttpPost]
    public ActionResult Index(string QRCode)
    {
        if (QRCode=="")
        {
            return Content("no value entered");
        }
        else
        {
            /*check to see if code is in database*/
            AssetLabel lbl = db.AssetLables.FirstOrDefault(q =>q.QRCode==QRCode);
            if (lbl != null)
            {
                var vm = new FinderViewModel();
                vm.AssetLabel = lbl;
                vm.Status = ConversationStatus.open;

                return View("FinderDetails", vm);
            }
            else
            {/*Label ID is not in the database*/
                return Content("Label Not Found");
            }
        }
    }

    [HttpPost]
    public ActionResult ProcessFinder(FinderViewModel vm)
    {
        /*
        THIS IS WHERE I AM STUCK! - vm.AssetLabel == NULL even though it
        was passed to the view with a fully populated object
        */
        return Content(vm.AssetLabel.QRCode.ToString());
        //return Content("Finder Details posted!");
    }

FinderView.cshtml

@model GMSB.ViewModels.FinderViewModel

@{
     ViewBag.Title = "TEST FINDER";
}

<h2>FinderDetails</h2>

@using (Html.BeginForm("ProcessFinder","Found",FormMethod.Post))
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
    <h4>Finder Details</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.ID)
    @Html.HiddenFor(model => model.AssetLabel)

    <div class="form-group">
        @Html.LabelFor(model => model.FinderName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FinderName, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FinderName, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.FinderMobile, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FinderMobile, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FinderMobile, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.FinderEmail, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FinderEmail, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FinderEmail, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
</div>

}

AssetLabel のレンダリングされた HTML スニペット

<input id="AssetLabel" name="AssetLabel" type="hidden"       
value="System.Data.Entity.DynamicProxies.AssetLabel_32653C4084FF0CBCFDBE520EA1FC5FE4F22B6D9CD6D5A87E7F1B7A198A59DBB3" 
/>
4

2 に答える 2

2

@Html.HiddenFor()を使用して、複雑なオブジェクトの隠し出力を生成することはできません。内部的.ToString()に生成するために使用するメソッドvalue(あなたの場合、出力はSystem.Data.Entity.DynamicProxies.AssetLabel_32653C4084FF0CBCFDBE520EA1FC5FE4F22B6D9CD6D5A87E7F1B7A198A59DBB3複雑なオブジェクトにバインドすることはできません)

-の各プロパティに対してフォーム コントロールを生成することもできますが、AssetLabelこれは非現実的です。これは、次AssetLabelのプロパティを含むコレクションでConversationあり、次のコレクションが含まれているためです。そのため、ネストされたループで各プロパティの入力を生成するConversationMessage必要があります。と。forConversationConversationMessage

しかし、大量の余分なデータをクライアントに送信し、それを変更せずに再度送信すると、パフォーマンスが低下し、データとデータ構造に関する不要な詳細が悪意のあるユーザーに公開され、悪意のあるユーザーがデータを変更する可能性があります)。

には、のプロパティ(または の ID プロパティ) とビューFinderViewModelが含まれている必要があります。QRCodeAssetLabel

@Html.HiddenFor(m => m.QRCode)

次に、POST メソッドで が必要な場合はAssetLabel、GET メソッドで行うのと同じようにリポジトリから再度取得します (ただし、POST メソッドで必要な理由は不明ですAssetLabel)。

補足として、ビューモデルにはビューで必要なプロパティのみを含める必要があり、データを編集するときにデータモデル (この場合はデータモデルから継承する) であるプロパティは含めないでください。MVC の ViewModel とは何ですか?を参照してください。. ビューに基づいて、4 つのプロパティFinderNameFinderMobileFinderEmailおよびQRCode(int? ID既存のオブジェクトの編集に使用する場合) が含まれている必要があります。

于 2016-11-12T21:59:51.077 に答える
0

ありがとうスティーブン。QRCode は AssetLabel の PK であり、Conversation の FK であるため、ワークフローを通じて追跡する必要があります。私はviewModelをジェネリックに保ち、この特定のフォームに密接に結合するのではなく、他のフォームに使用できるようにしようとしていました.AssetLabelを渡そうとしていました.繰り返したくありませんでした。私は何をする必要があるかを考え出しました - @Html.Hidden(model => model.AssetLabel.QRCode) を使用すると、フォーム フィールド名は AssetLabel_QRCode になり、POST ビューモデルの正しい場所に自動的にマップされます。コードの再利用を促進し、後でやり直しを避けるために、表示テンプレートにこのロジックを作成し、フィールドを非表示、次に @Html として定義しました。

@Html.Partial
(
    "./Templates/Assetlabel_hidden", 
    (GMSB.Models.AssetLabel)(Model.AssetLabel), 
    new ViewDataDictionary()
    {
        TemplateInfo = new TemplateInfo()
        {
            HtmlFieldPrefix = "AssetLabel"
        }
    }
)

しかし、あなたは完全に正しいです。これにより、追加のフィールドと私のアプリケーション構造が公開されます。必要なフィールドのみを公開するように viewModel を書き直して、AssetLabel 検証を最初の POST と後続の投稿の両方から呼び出すことができる別のプライベート関数に移動すると思います。これは、フラットな vm フィールドを複雑なオブジェクト グラフに手動でマップする必要があるため、コントローラーに余分なコードが必要になることを意味します。

于 2016-11-12T22:36:20.747 に答える