ASP.NET MVC-モデルがカスタムViewModelにラップされていない場合、フォームはNullモデルを返します

StackOverflow https://stackoverflow.com/questions/1821302

質問

アプリケーションには、モデル項目の1つに対して同じエディターテンプレートを表示するビューのペアがあります。 2つのビュー("追加"と"編集")、"編集"正常に動作しますが、「追加」コントローラーアクションが投稿を処理するときにモデルにnullを返します。

「追加」を与えると、 Modelオブジェクト全体でEditorFor()を呼び出すのではなく、カスタムViewModelを表示して Html.EditorFor(p => p.PageContent)を呼び出します- Html.EditorFor(p => p)の場合、フォームは正しい非nullモデルを返しますが、クライアント側のスクリプティングIDとコントロールIDに関連する他の問題が発生します(現在、すべてのフィールドには" PageContent_"が付いています)。私はアプリケーション全体のいくつかの異なる場所で同じEditor Templateテクニックを使用していますが、ViewModelにこの奇妙な依存関係を示しているものはありません。

他の誰かが同様の問題を経験したことはありますか?

ビューの編集

<%@ Page Title="" Language="C#" MasterPageFile="~/Areas/Admin/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<PageContent>" %>

<% using (Html.BeginForm())
   { %>
<%=Html.Hidden("PageID", Model.Page.ID) %>
<%=Html.EditorFor(p => p)%>
<input type="submit" name="btnSave" value="Save" />
<input type="submit" name="btnCancel" value="Cancel" class="cancel" />
<% }

アクション(動作中)

[HttpPost, ValidateInput(false)]
public ActionResult EditContent(int id, FormCollection formCollection) {}

ビューを追加

<%@ Page Title="" Language="C#" MasterPageFile="~/Areas/Admin/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<PageContent>" %>

<% using (Html.BeginForm())
   { %>
<%=Html.Hidden("PageID", ViewData["PageID"]) %>
<%=Html.EditorFor(p => p)%>
<input type="submit" name="btnSave" value="Save" />
<input type="submit" name="btnCancel" value="Cancel" class="cancel" />
<% } %>

アクション(失敗)

// content is ALWAYS null
[HttpPost, ValidateInput(false)]
public ActionResult AddContent(PageContent content, FormCollection formCollection) {}

泣く前に&quot;複製&quot;

この質問はこれに関連していますが、この質問より一般的な質問ではなく、私が経験している特定の問題を対象としています。

役に立ちましたか?

解決

問題を追跡しましたが、かなり興味深い問題です。

DefaultModelBinderがモデルアイテムを解決しようとするとき、最初に行うことの1つは、バインドされているデータにプレフィックスフィールドがあるかどうかを確認することです。これは、モデルオブジェクトの名前で始まるフォームアイテムをチェックすることで行われます(私に尋ねると、これは非常にarbitrary意的のようです)。 「接頭辞付き」がある場合フィールドが見つかると、異なるバインディングロジックが呼び出されます。

ASP.NET MVC 2 Preview 2 BindModel()Source

public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
    if (bindingContext == null) {
        throw new ArgumentNullException("bindingContext");
    }
    bool performedFallback = false;
    if (!String.IsNullOrEmpty(bindingContext.ModelName) && !DictionaryHelpers.DoesAnyKeyHavePrefix(bindingContext.ValueProvider, bindingContext.ModelName)) {
        // We couldn't find any entry that began with the prefix. If this is the top-level element, fall back
        // to the empty prefix.
        if (bindingContext.FallbackToEmptyPrefix) {
             /* omitted for brevity */
            };
            performedFallback = true;
        }
        else {
            return null;
        }
    }

    // Simple model = int, string, etc.; determined by calling TypeConverter.CanConvertFrom(typeof(string))
    // or by seeing if a value in the request exactly matches the name of the model we're binding.
    // Complex type = everything else.
    if (!performedFallback) {
       /* omitted for brevity */
    }
    if (!bindingContext.ModelMetadata.IsComplexType) {
        return null;
    }
    return BindComplexModel(controllerContext, bindingContext);
}

Addアクションを処理するために定義したコントローラーアクションは、&quot; content&quot;と呼ばれるPageContentアイテムを定義します。私のドメインにはPageContentに&quot; Content&quot;というプロパティがあります「一致」したものモデル名が「content」の場合したがって、DefaultModelBinderは、実際には単なるPageContentのメンバーであるにもかかわらず、接頭辞付きの値を持っていると想定します。署名を変更することで

from:

[HttpPost, ValidateInput(false)]
public ActionResult AddContent(PageContent content, FormCollection formCollection) {}

宛先:

[HttpPost, ValidateInput(false)]
public ActionResult AddContent(PageContent pageContent, FormCollection formCollection) {}

DefaultModelBinderは、再びPageContentモデルアイテムに正しくバインドできました。編集ビューにもこの動作が表示されなかった理由はわかりませんが、どちらにしても問題の原因を突き止めました。

この問題は「バグ」に非常に近いようです。状態。 「コンテンツ」が最初にViewModelで機能するのは理にかなっています。 &quot; PageContent_&quot;という接頭辞が付けられていましたが、このようなコアフレームワークの機能/バグは修正されていないはずです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top