2013-11-21 8 views
6

So habe ich einen Controller wie folgt aus:ASP.NET MVC Beitrag Liste wird unter sehr merkwürdigen Umständen null

public class TestController : Controller 
    { 
     // 
     // GET: /Test/ 

     public ActionResult Index() 
     { 
      return View("Test"); 
     } 

     public ActionResult Post(IList<Test> LanguageStrings, IList<Test> LanguageStringsGroup, IList<string> Deleted, IList<string> DeletedGroup) 
     { 
      if (LanguageStrings == null) 
      { 
       throw new ApplicationException("NULL"); 
      } 


      return View("Test"); 
     } 

    } 

    public class Test 
    { 
     public string Val { get; set; } 
     public string Another { get; set; } 
    } 

Und eine Ansicht wie folgt aus:

<h2>Test</h2> 

@using (Html.BeginForm("Post", "Test")) 
{ 
    @Html.Hidden("LanguageStrings[0].Val", "test1") 
    @Html.Hidden("LanguageStrings[0].Another") 
    @Html.Hidden("LanguageStrings[1].Val", "test2") 
    @Html.Hidden("LanguageStrings[1].Another") 

    @Html.Hidden("LanguageStringsGroup[0].Val", "test4") 

    @Html.Hidden("Deleted[0]") 
    @Html.Hidden("Deleted[1]") 
    @Html.Hidden("Deleted[2]") 

    @Html.Hidden("DeletedGroup[0]") 

    <button>Post</button> 
} 

Wenn ich poste das Formular mein Controller löst die Ausnahme aus, weil LanguageStrings null ist. Der seltsame Teil, den ich im Titel erwähnt habe, ist, dass alles funktioniert, wenn ich einen weiteren Datensatz zur Liste hinzufüge. So:

<h2>Test</h2> 

@using (Html.BeginForm("Post", "Test")) 
{ 
    @Html.Hidden("LanguageStrings[0].Val", "test1") 
    @Html.Hidden("LanguageStrings[0].Another") 
    @Html.Hidden("LanguageStrings[1].Val", "test2") 
    @Html.Hidden("LanguageStrings[1].Another") 
    @Html.Hidden("LanguageStrings[2].Val", "test3") 
    @Html.Hidden("LanguageStrings[2].Another") 

    @Html.Hidden("LanguageStringsGroup[0].Val", "test4") 

    @Html.Hidden("Deleted[0]") 
    @Html.Hidden("Deleted[1]") 
    @Html.Hidden("Deleted[2]") 

    @Html.Hidden("DeletedGroup[0]") 

    <button>Post</button> 
} 

Es funktioniert auch, wenn ich die „Gelöscht“ Liste zu entfernen. So:

<h2>Test</h2> 

@using (Html.BeginForm("Post", "Test")) 
{ 
    @Html.Hidden("LanguageStrings[0].Val", "test1") 
    @Html.Hidden("LanguageStrings[0].Another") 
    @Html.Hidden("LanguageStrings[1].Val", "test2") 
    @Html.Hidden("LanguageStrings[1].Another") 

    @Html.Hidden("LanguageStringsGroup[0].Val", "test4") 

    @Html.Hidden("DeletedGroup[0]") 

    <button>Post</button> 
} 

Das hat etwas mit der Namensgebung zu tun, ich bin mit. Ich habe das Problem mit dem Umbenennen von LanguageStrings zu etwas anderem bereits gelöst. Aber ich würde gerne verstehen, was hier passiert, denn wahrscheinlich könnte ich etwas daraus lernen, wie MVC den Anfragekörper abbildet und ähnliche zeitraubende Probleme vermeiden kann. Bitte helfen Sie mir und erklären Sie die Ursache dafür.

Antwort

5

Sie fanden einen Fehler in dem PrefixContainer von MVC 4, die bereits in MVC wird behoben 5.

Hier ist die feste Version mit Kommentare über den Fehler:

internal bool ContainsPrefix(string prefix) 
{ 
    if (prefix == null) 
    { 
     throw new ArgumentNullException("prefix"); 
    } 

    if (prefix.Length == 0) 
    { 
     return _sortedValues.Length > 0; // only match empty string when we have some value 
    } 

    PrefixComparer prefixComparer = new PrefixComparer(prefix); 
    bool containsPrefix = Array.BinarySearch(_sortedValues, prefix, prefixComparer) > -1; 
    if (!containsPrefix) 
    { 
     // If there's something in the search boundary that starts with the same name 
     // as the collection prefix that we're trying to find, the binary search would actually fail. 
     // For example, let's say we have foo.a, foo.bE and foo.b[0]. Calling Array.BinarySearch 
     // will fail to find foo.b because it will land on foo.bE, then look at foo.a and finally 
     // failing to find the prefix which is actually present in the container (foo.b[0]). 
     // Here we're doing another pass looking specifically for collection prefix. 
     containsPrefix = Array.BinarySearch(_sortedValues, prefix + "[", prefixComparer) > -1; 
    } 
    return containsPrefix; 
} 
+0

wo sollte dieser Code gehen ?? – raklos

+0

MVC5 hat diesen Code, also nur auf MVC5 aktualisieren. Hier ist der neueste Quellcode von PrefixContainer https://aspnetwebstack.codeplex.com/SourceControl/latest#src/Common/PrefixContainer.cs – LostInComputer

0

Ich hatte viel mehr Erfolg mit @ Html.HiddenFor() zum Zurücksetzen auf den Controller. Code würde wie folgt aussehen:

@for (int i = 0; i < @Model.LanguageStrings.Count; i++) 
{ 
    @Html.HiddenFor(model => model.LanguageStrings[i].Val, string.Format("test{0}", i)) 
    @Html.HiddenFor(model => model.LanguageStrings[i].Another) 
} 

Die meisten HTML-Hilfsmethoden a „für“ Helfer haben, die für die Bindung von Daten an Modellen verwendet werden soll. Hier ist ein weiterer Beitrag auf der Website, die die „For“ Methoden gut erklärt: What is the difference between Html.Hidden and Html.HiddenFor

Verwandte Themen