Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
532 views
in Technique[技术] by (71.8m points)

asp.net - MVC ViewModel Error - No parameterless constructor defined for this object

I would like to know how can I use my ViewModel on the Create Action? I tried several examples I found here in the forum, but none solved my problem. I've been racking my brain for a few days, but can't figure out what is wrong.

Whenever I click the Create button I get the following error: No parameterless constructor defined for this object.

@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; }
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If I had a nickel for every time I've seen this problem. It's typically related to the naming of your model properties and how you use them in a DropDownList. 99.999% of the time it's because people are using Html.DropDownList() and naming it the same as their SelectList. This is one reason you should use the strongly typed DropDownListFor.

In this case, your problem is that you have SelectLists named Genres and Artists, then in your view you have:

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

See, same name.

What you should do is change your Model to make the SelectLists be named GenreList and ArtistList. Then, change your view to use strongly typed model.

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

The reason this happens is that you are posting a value called Genres to the controller. The default model binder dutifully looks in the model to find something called Genres and instantiate it. But, rather than an ID or string, it finds a SelectList named Genres, and when it tries to instantiate it, it finds there is no default constructor.

Thus your error. SO is filled with questions asking about this same thing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...