ASP.NET MVC – Formular gibt Nullmodell zurück, es sei denn, das Modell ist in ein benutzerdefiniertes ViewModel eingeschlossen

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

Frage

Ich habe in meiner Anwendung zwei Ansichten, die beide dieselbe Editor-Vorlage für eines meiner Modellelemente anzeigen.Von den beiden Ansichten („Hinzufügen“ und „Bearbeiten“) funktioniert „Bearbeiten“ einwandfrei, aber „Hinzufügen“ gibt für das Modell null zurück, wenn meine Controller-Aktion den Beitrag verarbeitet.

Ich habe festgestellt, dass ich der Ansicht „Hinzufügen“ ein benutzerdefiniertes ViewModel gebe und aufrufe Html.EditorFor(p => p.PageContent) anstatt einfach EditorFor() für das gesamte Modellobjekt aufzurufen. Html.EditorFor(p => p), dann gibt das Formular das richtige Nicht-Null-Modell zurück, aber das führt zu anderen Problemen im Zusammenhang mit meiner clientseitigen Skripterstellung und meinen Steuerelement-IDs (da jetzt allen Feldern das Präfix „PageContent_“ vorangestellt ist).Ich verwende die gleiche Editor-Vorlagentechnik an einigen verschiedenen Stellen in meiner Anwendung und keine der anderen weist diese seltsame Abhängigkeit von einem ViewModel auf.

Hat jemand anderes jemals ähnliche Probleme gehabt?

Ansicht bearbeiten

<%@ 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" />
<% }

Aktion (funktioniert)

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

Ansicht hinzufügen

<%@ 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" />
<% } %>

Aktion (fehlgeschlagen)

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

Bevor du „Duplikat“ schreist

Diese Frage bezieht sich auf Dieses hier, aber diese Frage soll auf das spezifische Problem abzielen, das ich habe, und nicht auf die allgemeinere Frage, die dort gestellt wird.

War es hilfreich?

Lösung

Ich habe das Problem aufgespürt und es ist ziemlich interessant.

Wenn der DefaultModelBinder versucht, ein Modellelement aufzulösen, prüft er zunächst, ob in den zu bindenden Daten Präfixfelder vorhanden sind.Dazu wird nach Formularelementen gesucht, die mit dem Namen des Modellobjekts beginnen (dies scheint äußerst willkürlich, wenn Sie mich fragen).Wenn „präfixierte“ Felder gefunden werden, führt dies dazu, dass eine andere Bindungslogik aufgerufen wird.

ASP.NET MVC 2 Vorschau 2 BindModel() Quelle

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);
}

Die Controller-Aktion, die ich zur Verarbeitung der Aktion „Hinzufügen“ definiert habe, definiert ein PageContent-Element namens „content“ und in meiner Domäne verfügt PageContent über eine Eigenschaft namens „Content“, die mit dem Modellnamen „content“ „übereinstimmt“, wodurch der DefaultModelBinder davon ausgeht, dass ich es getan habe ein vorangestellter Wert, obwohl es sich in Wirklichkeit lediglich um ein Mitglied von PageContent handelte.Durch Ändern der Signatur-

aus:

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

Zu:

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

Der DefaultModelBinder konnte wieder korrekt an mein PageContent-Modellelement binden.Ich bin mir nicht sicher, warum dieses Verhalten nicht auch in der Bearbeitungsansicht angezeigt wurde, aber so oder so habe ich die Ursache des Problems ausfindig gemacht.

Mir scheint, dass dieses Problem dem Status „Bug“ sehr nahe kommt.Es macht Sinn, dass meine Ansicht anfangs mit dem ViewModel funktionierte, weil „content“ das Präfix „PageContent_“ erhielt, aber eine Kern-Framework-Funktion/ein solcher Fehler sollte meiner Meinung nach nicht unberücksichtigt bleiben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top