How do I transfer ViewModel data between POST requests in ASP.NET MVC?

青春壹個敷衍的年華 提交于 2019-12-14 03:53:33

问题


I have a ViewModel like so:

public class ProductEditModel
{
    public string Name { get; set; }
    public int CategoryId { get; set; }
    public SelectList Categories { get; set; }

    public ProductEditModel()
    {
        var categories = Database.GetCategories(); // made-up method
        Categories = new SelectList(categories, "Key", "Value");
    }
}

Then I have two controller methods that uses this model:

public ActionResult Create()
{
    var model = new ProductEditModel();
    return View(model);
}

[HttpPost]
public ActionResult Create(ProductEditModel model)
{
    if (ModelState.IsValid)
    {
        // convert the model to the actual entity
        var product = Mapper.Map(model, new Product());
        Database.Save(product);
        return View("Success");
    }
    else
    {
        return View(model); // this is where it fails
    }
}

The first time the user goes to the Create view, they are presented with a list of categories. However, if they fail validation, the View is sent back to them, except this time the Categories property is null. This is understandable because the ModelBinder does not persist Categories if it wasn't in the POST request. My question is, what's the best way of keeping Categories persisted? I can do something like this:

[HttpPost]
public ActionResult Create(ProductEditModel model)
{
    if (ModelState.IsValid)
    {
        // convert the model to the actual entity
        var product = Mapper.Map(model, new Product());
        Database.Save(product);
        return View("Success");
    }
    else
    {
        // manually populate Categories again if validation failed
        model.Categories = new SelectList(categories, "Key", "Value");
        return View(model); // this is where it fails
    }
}

But this is an ugly solution. How else can I persist it? I can't use a hidden field because it's a collection.


回答1:


I typically implement my lists (for drop downs) as a readonly property. When the View gets the value the property is self contained on what it needs to return the values.

public SelectList Categories
{
    get
    {
        var categories = Database.GetCategories(); // made-up method
        return new SelectList(categories, "Key", "Value");
    }
}

If necessary you can grab the currently selected item (i.e. validation failed) from the property containing the id that was posted and bound to the instance of your class.




回答2:


I would use the repository to fetch whatever data is needed and don't think it's an ugly solution:

[HttpPost]
public ActionResult Create(ProductEditModel model)
{
    if (!ModelState.IsValid)
    {
        // manually populate Categories again if validation failed
        model.Categories = Repository.GetCategories();
        return View(model);
    }

    // convert the model to the actual entity
    var product = Mapper.Map(model, new Product());
    Database.Save(product);

    // I would recommend you to redirect here
    return RedirectToAction("Success");
}

To further refactor this I would recommend you watching the excellent Putting Your Controllers on a Diet video presentation by Jimmy Bogard.




回答3:


In my case I have a BaseModel class where I keep all those property list as class attributes.

Like in the following sample:

public IEnumerable<SelectListItem> CountryList
{
    get
    {
        return GetCountryList().Select(
            t => new SelectListItem { Text = t.Name, Value = Convert.ToString(t.CountryID) });
    }
}

GetCountryList() is a function that ask a Singleton for data. This would only happen once in the app lifecycle

Another way for doing this, and if those lists are pretty big, would be to have a static utility class with the lookup table that returns the SelectListItem.

If you need to access a list that change from time to time then simply dont use a Singleton class.



来源:https://stackoverflow.com/questions/4190866/how-do-i-transfer-viewmodel-data-between-post-requests-in-asp-net-mvc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!