【发布时间】:2020-10-20 15:02:17
【问题描述】:
我查看并实施了类似主题的解决方案,但不幸的是他们没有为我提供解决方案。
错误信息:
InvalidOperationException:传递到 ViewDataDictionary 的模型项属于“CMS.Models.Page”类型,但此 ViewDataDictionary 实例需要“System.Collections.Generic.IEnumerable`1[CMS.Models.Page] 类型的模型项'。
我正在开发一个简单的 cms。我的目标是在列出我的页面后对它们进行一些更改。
一段时间以来,我一直在尝试修复该错误,但我无法从我应用的解决方案中获得任何结果。我的猜测是这里的模型结构的数据通信问题。在我的代码下方:
家庭控制器:
public class HomeController : Controller
{
private readonly ApplicationDbContext _dbContext;
public HomeController(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public IActionResult Index()
{
var page = _dbContext.Pages.FirstOrDefault(x => x.Title == "Home");
return View(page);
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
管理员控制器:
public class AdminController : Controller
{
private readonly ApplicationDbContext _context;
public AdminController(ApplicationDbContext context)
{
_context = context;
}
// GET: Pages
public async Task<IActionResult> Index()
{
return View(await _context.Pages.ToListAsync());
}
public async Task<IActionResult> EditPage(string title)
{
// SELECT * FROM Pages WHERE Title = {title}
var page = await _context.Pages.FirstOrDefaultAsync(x => x.Title == title);
if (page == null)
{
page = new Page();
page.Title = title;
_context.Pages.Add(page);
_context.SaveChanges();
}
return View(page);
}
// GET: Pages/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var page = await _context.Pages
.FirstOrDefaultAsync(m => m.ID == id);
if (page == null)
{
return NotFound();
}
return View(page);
}
// GET: Pages/Create
public IActionResult Create()
{
return View();
}
// POST: Pages/Create
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Title,Content,Section")] Page page)
{
if (ModelState.IsValid)
{
_context.Add(page);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(page);
}
// GET: Pages/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var page = await _context.Pages.FindAsync(id);
if (page == null)
{
return NotFound();
}
return View(page);
}
// POST: Pages/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Title,Content,Section")] Page page)
{
if (id != page.ID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(page);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!PageExists(page.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(page);
}
// GET: Pages/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var page = await _context.Pages
.FirstOrDefaultAsync(m => m.ID == id);
if (page == null)
{
return NotFound();
}
return View(page);
}
// POST: Pages/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var page = await _context.Pages.FindAsync(id);
_context.Pages.Remove(page);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool PageExists(int id)
{
return _context.Pages.Any(e => e.ID == id);
}
}
我无法查看的页面 => EditPage:
@model IEnumerable<piktusCMS.Models.Page>
@{
ViewData["Title"] = "Edit Page";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Content)
</th>
<th>
@Html.DisplayNameFor(model => model.Section)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Content)
</td>
<td>
@Html.DisplayFor(modelItem => item.Section)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
页面模型:
public class Page
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public string Section { get; set; }
}
数据库上下文:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Page> Pages { get; set; }
}
提前感谢您的解决方案和建议
【问题讨论】:
-
错误很明显。您将单个
CMS.Models.Page对象传递给您的EditPage视图,而您的视图需要IEnumerable<CMS.Models.Page>。 -
错误很明显 - 您正在尝试传递单个项目来查看需要收集的项目。要么更改视图以使用单个项目,要么从控制器返回集合。
-
我解决了,谢谢大家。正如你在
EditPage行动中所说的那样,我把它当作一个清单。我没注意到return(page)。我更新为await _context.Pages.ToListAsync()。 -
思考;并回顾您的最后评论和受答案启发的更改 - lbracadabra - 如果您不需要它,请不要查询整个列表。如果您不想更改视图中的
@model,只需执行return View(new [] {page})。当您有理由偏离提供的,接受答案时,您应该提出偏离该答案的考虑和推理(特别是如果该答案忽略了解决异常的方法不止一种但与您的情况相关) .改进问题和答案是一个迭代过程。
标签: c# asp.net asp.net-mvc asp.net-core model-view-controller