2012-10-03 10 views
8

Ich würde gerne wissen, wie kann ich mein ViewModel auf die Aktion erstellen verwenden? Ich habe einige Beispiele aus dem Forum ausprobiert, aber keines hat mein Problem gelöst. Ich habe mir ein paar Tage lang den Kopf zerbrochen, kann aber nicht herausfinden, was falsch ist.MVC ViewModel Fehler - Kein parameterloser Konstruktor für dieses Objekt definiert

Immer wenn ich auf die Schaltfläche Erstellen klicke, erhalte ich folgende Fehlermeldung: Für dieses Objekt wurde kein parameterloser Konstruktor definiert.

@model MvcMusicStore.ViewModels.AlbumViewModel 

@{ 
    ViewBag.Title = "Create"; 
} 

<h2>Create</h2> 

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 

@using (Html.BeginForm()) { 
    @Html.ValidationSummary(true) 
    <fieldset> 
     <legend>Album</legend> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.GenreId, "Genre") 
     </div> 
     <div class="editor-field"> 
      @Html.DropDownList("Genres", String.Empty) 
      @Html.ValidationMessageFor(model => model.AlbumItem.GenreId) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.ArtistId, "Artist") 
     </div> 
     <div class="editor-field"> 
      @Html.DropDownList("Artists", String.Empty) 
      @Html.ValidationMessageFor(model => model.AlbumItem.ArtistId) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.Title) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.AlbumItem.Title) 
      @Html.ValidationMessageFor(model => model.AlbumItem.Title) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.Price) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.AlbumItem.Price) 
      @Html.ValidationMessageFor(model => model.AlbumItem.Price) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.AlbumItem.AlbumArtUrl) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.AlbumItem.AlbumArtUrl) 
      @Html.ValidationMessageFor(model => model.AlbumItem.AlbumArtUrl) 
     </div> 

     <p> 
      <input type="submit" value="Create" /> 
     </p> 
    </fieldset> 
} 

<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

Create.cshtml

public class StoreManagerController : Controller 
     { 
      private MusicStoreDB db = new MusicStoreDB(); 

      // 
      // GET: /StoreManager/Create 

      public ActionResult Create() 
      { 
       var viewModel = new AlbumViewModel() 
       { 
        Genres = new SelectList(db.Genres, "GenreId", "Name"), 
        Artists = new SelectList(db.Artists, "ArtistId", "Name") 
       }; 
       return View(viewModel); 
      } 

      // 
      // POST: /StoreManager/Create 

      [HttpPost] 
      public ActionResult Create(AlbumViewModel vm) 
      { 
       if (ModelState.IsValid) 
       { 
        db.Albums.Add(vm.AlbumItem); 
        db.SaveChanges(); 
        return RedirectToAction("Index"); 
       } 

       vm.Genres = new SelectList(db.Genres, "GenreId", "Name", vm.AlbumItem.GenreId); 
       vm.Artists = new SelectList(db.Artists, "ArtistId", "Name", vm.AlbumItem.ArtistId); 
       return View(vm); 
      } 
} 

StoreManager.cs - Snippet

public class AlbumViewModel 
    { 
     public AlbumViewModel() 
     { 
      // nothing 
     } 

     public Album AlbumItem { get; set; } 
     public SelectList Genres { get; set; } 
     public SelectList Artists { get; set; } 
    } 

public class Album 
    { 
     public Album() 
     { 
      // nothing 
     } 

     public virtual int AlbumId { get; set; } 
     public virtual int GenreId { get; set; } 
     public virtual int ArtistId { get; set; } 
     public virtual string Title { get; set; } 
     public virtual decimal Price { get; set; } 
     public virtual string AlbumArtUrl { get; set; } 
     public virtual Genre Genre { get; set; } 
     public virtual Artist Artist { get; set; } 
    } 

public class Artist 
    { 
     public Artist() 
     { 
      // nothing 
     } 

     public virtual int ArtistId { get; set; } 
     public virtual string Name { get; set; } 
    } 

public class Genre 
    { 
     public Genre() 
     { 
      // nothing 
     } 

     public virtual int GenreId { get; set; } 
     public virtual string Name { get; set; } 
     public virtual string Description { get; set; } 
     public virtual List<Album> Albums { get; set; } 
    } 
+1

Was ist 'Genre'? – SLaks

+0

"Genre" und "Künstler" im obigen Code hinzugefügt. – fvss

+0

Die einzige Sache, die keinen parameterlosen Konstruktor zu haben scheint, ist die SelectList (http://msdn.microsoft.com/en-us/library/system.web.mvc.selectlist(v=vs.108).aspx). Was, wenn Sie diese kommentieren? –

Antwort

24

Wenn ich ein Nickel für jedes Mal hatte ich dieses Problem gesehen habe. Es bezieht sich normalerweise auf die Benennung Ihrer Modelleigenschaften und darauf, wie Sie sie in einem DropDownList verwenden. 99.999% der Zeit ist es, weil Leute Html.DropDownList() verwenden und benennen sie das gleiche wie ihre SelectList. Dies ist ein Grund, warum Sie die stark typisierte DropDownListFor verwenden sollten.

In diesem Fall Ihr Problem ist, dass Sie SelectList s genannt Genres und Artists, dann in der Ansicht, die Sie haben müssen:

@Html.DropDownList("Genres", String.Empty) 
@Html.DropDownList("Artists", String.Empty) 

See, gleiche Namen.

Was Sie tun sollten, ist Ihr Modell so zu ändern, dass die SelectList s GenreList und ArtistList heißen. Ändern Sie dann Ihre Ansicht, um ein stark typisiertes Modell zu verwenden.

@Html.DropDownListFor(m => m.AlbumItem.GenreID, Model.GenreList) 
@Html.DropDownListFor(m => m.AlbumItem.ArtistID, Model.ArtistList) 

Der Grund dafür ist, dass Sie einen Wert namens Genres an den Controller senden. Der Standardmodellbinder sucht pflichtgemäß im Modell nach etwas namens Genres und instanziiert es. Aber statt einer ID oder einer Zeichenfolge wird eine SelectList mit dem Namen "Genres" gefunden. Wenn sie versucht, sie zu instanziieren, findet sie keinen Standardkonstruktor.

Also Ihr Fehler. SO ist gefüllt mit Fragen, die nach dem gleichen Thema fragen.

+0

Das war's! Vielen Dank! – fvss

+0

Das gleiche hier. Du hast meine Stunden gerettet –

0

Ähnlich Erik Funkenbusch's answer hatte ich ein Dropdownlist zu meiner Form, aber in meinem Fall hinzugefügt war es nicht (und wurde nicht bestimmt) mit dem Formular übermittelt, wie es außerhalb der <form></form> Tags war:

@Html.DropDownList("myField", Model.MyField) 

Da das Modell nur das Feld für die Anzeige enthielt, führte dies auch zum Fehler No parameterless constructor defined for this object, da das Feld überhaupt nicht übergeben wurde.

In diesem Fall fixiert ich es durch Hinzufügen eines ausschließen Bindung:

public ActionResult Foo(int id, int? page, [Bind(Exclude = "MyField")]MyModel model) 
0

Für mich ist das Problem in der Begin() -Methode selbst war. Es sah so aus:

@using (Html.BeginForm("MyAccount", "MyController", Model)) 

Kopiert und eingefügt von der Anmeldeseite eines anderen Projekts, die kein Dropdown hat.

Wie auch immer, entfernen Sie das Modell aus der Parameterliste und alles funktioniert gut :)

Verwandte Themen