'Pass list item wih viewmodel in .net core
I'm new to this and this might be quite easy for some people. I'm struggling to connect a particular field (dropdown list item) between a View and a Controller. What I'm pretending is to associate a category (from a list) to a product.
For this particular Controller, my system as a Model, a Service and a ViewModel.
For the product class I have the following code:
public class DryGoodsProduct
{
public int Id { get; set; }
public string ProductName { get; set; }
[Display(Name = "Category")]
[Required]
public DryGoodsCategory DryGoodsCategory { get; set; }
public int DryGoodsCategoryId { get; set; }
public DryGoodsProduct()
{ }
public DryGoodsProduct(int id, string productName, DryGoodsCategory category)
{
Id = id;
ProductName = productName;
DryGoodsCategory = category;
}
}
The category class is the following:
public class DryGoodsCategory
{
public int Id { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public virtual ICollection<DryGoodsProduct> DryGoodsProducts { get; set; }
public DryGoodsCategory()
{
}
public DryGoodsCategory(int id, string categoryName)
{
Id = id;
CategoryName = categoryName;
}
}
The product service class is the following:
public class DryGoodsProductService
{
private readonly DB _context;
public DryGoodsProductService(DB context)
{
_context = context;
}
public async Task<List<DryGoodsProduct>> FindAllAsync()
{
return await _context.DryGoodsProducts
.Include(obj => obj.DryGoodsCategory)
.ToListAsync();
}
public async Task InsertAsync(DryGoodsProduct drygoodsProduct)
{
_context.Add(drygoodsProduct);
await _context.SaveChangesAsync();
}
public async Task<DryGoodsProduct> FindByIdAsync(int id)
{
return await _context.DryGoodsProducts
.Include(obj => obj.DryGoodsCategory)
.FirstOrDefaultAsync(x => x.Id == id);
}
public async Task RemoveAsync(int id)
{
try
{
var obj = await _context.DryGoodsProducts.FindAsync(id);
_context.DryGoodsProducts.Remove(obj);
await _context.SaveChangesAsync();
}
catch (IntegrityException e)
{
throw new IntegrityException(e.Message);
}
}
public async Task UpdateAsync(DryGoodsProduct drygoodsProduct)
{
bool hasAny = await _context.DryGoodsProducts.AnyAsync(x => x.Id == drygoodsProduct.Id);
if (!hasAny)
{
throw new NotFoundException("ID não encontrado");
}
try
{
_context.Update(drygoodsProduct);
await _context.SaveChangesAsync();
}
catch (DbConcurrencyException ex)
{
throw new DbConcurrencyException(ex.Message);
}
}
}
and the view model class is:
public class DryGoodsProductViewModel
{
public DryGoodsProduct drygoodsProduct { get; set; }
public virtual ICollection<DryGoodsCategory> DryGoodsCategories { get; set; }
}
the controller is the following:
public async Task<IActionResult> Create()
{
var categories = await _categoryService.FindAllAsync();
var product = new DryGoodsProduct();
var viewmodel = new DryGoodsProductViewModel()
{
drygoodsProduct = product,
DryGoodsCategories = categories,
};
return View(viewmodel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(DryGoodsProduct product)
{
if (ModelState.IsValid)
{
await _productService.InsertAsync(product);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(product);
}
and the create view :
enter @model Library.ViewModels.Logistics.DryGoodsProductViewModel
@{
ViewData["Title"] = "Create";
Layout = "~/Areas/Logistics/Views/Shared/_LogisticsLayout.cshtml"; }
<h1>Create</h1>
<h4>Products</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create" enctype="multipart/form-data">
@Html.AntiForgeryToken()
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="drygoodsProduct.ProductName" class="control-label"></label>
<input asp-for="drygoodsProduct.ProductName" class="form-control" />
<span asp-validation-for="drygoodsProduct.ProductName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="drygoodsProduct.DryGoodsCategoryId" class="control-label"></label>
<select asp-for="drygoodsProduct.DryGoodsCategoryId" asp-items="@(new SelectList(Model.DryGoodsCategories, "Id", "CategoryName"))" class="form-control"></select>
<span asp-validation-for="drygoodsProduct.DryGoodsCategoryId" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
So... The error says:
An unhandled exception occurred while processing the request. InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'Library.Models.Logistics.DryGoods.DryGoodsProduct', but this ViewDataDictionary instance requires a model item of type 'Library.ViewModels.Logistics.DryGoodsProductViewModel'.
I mean, I've done something quit similar with another controller and everything is ok.
I would appreciate some feedback on how to solve this.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
