c# - 没有数据库的 ASP.NET MVC
问题描述
我正在尝试在没有数据库的情况下在 MVC 上创建一个完整的 CRUD 应用程序。我将模板视图创建器用于“创建/详细信息/编辑/删除...”我无法保存/编辑/删除,因为大多数在线资源都来自数据库/框架。对于“创建”,在输入所有字段后,它会将我带回到所有PersonModel的“列表”页面,而没有新输入的PersonModel。我无法让[HttpPost]进行编辑。
using MVCDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCDemo.Controllers
{
public class PersonController : Controller
{
List<PersonModel> people = new List<PersonModel>()
{
new PersonModel { First = "DAD", Last = "Nguyen", Name = "Study", About = "Study for test", Done = false, Id = 1 },
new PersonModel { First = "David", Last = "Smith", Name = "Grocery", About = "Buy apple and bananana", Done = true , Id = 2},
new PersonModel { First = "Tom", Last = "Davidson", Name = "Fix car", About = "Headlight and mirror is broken", Done = false, Id = 3 },
new PersonModel { First = "Maddie", Last = "Madison", Name = "Job application", About = "Follow up on job interview ", Done = false , Id = 4}
};
// GET: Person
public ActionResult Index()
{
return View(people);
}
[HttpGet]
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(PersonModel per)
{
try
{
if (!ModelState.IsValid)
{
return View("Create", per);
}
people.Add(per);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
public ActionResult Details(int id)
{
PersonModel per = people.Find(emp => emp.Id == id);
return View(per);
}
[HttpGet]
public ActionResult Edit(int id)
{
PersonModel per = people.Find(emp => emp.Id == id);
return View(per);
}
public ActionResult Delete()
{
return View();
}
}
}
谢谢你。
编辑
类模型
public class PersonModel
{
public int Id { get; set; }
public string First { get; set; }
public string Last { get; set; }
public bool Done { get; set; }
public string Name { get; set; }
public string About { get; set; }
}
索引 cshtml
@model IEnumerable<MVCDemo.Models.PersonModel>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.First)
</th>
<th>
@Html.DisplayNameFor(model => model.Last)
</th>
<th>
@Html.DisplayNameFor(model => model.Done)
</th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.About)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.First)
</td>
<td>
@Html.DisplayFor(modelItem => item.Last)
</td>
<td>
@Html.DisplayFor(modelItem => item.Done)
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.About)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
@Html.ActionLink("Details", "Details", new { id=item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
创建cshtml
@model MVCDemo.Models.PersonModel
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PersonModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.First, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.First, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.First, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Last, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Last, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Last, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Done, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
@Html.EditorFor(model => model.Done)
@Html.ValidationMessageFor(model => model.Done, "", new { @class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.About, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.About, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.About, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
详情 cshtml
@model MVCDemo.Models.PersonModel
@{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>PersonModel</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.First)
</dt>
<dd>
@Html.DisplayFor(model => model.First)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Last)
</dt>
<dd>
@Html.DisplayFor(model => model.Last)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Done)
</dt>
<dd>
@Html.DisplayFor(model => model.Done)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.About)
</dt>
<dd>
@Html.DisplayFor(model => model.About)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
编辑 cshtml
@model MVCDemo.Models.PersonModel
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PersonModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)
<div class="form-group">
@Html.LabelFor(model => model.First, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.First, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.First, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Last, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Last, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Last, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Done, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
@Html.EditorFor(model => model.Done)
@Html.ValidationMessageFor(model => model.Done, "", new { @class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.About, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.About, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.About, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
解决方案
正如评论中指出的,控制器实例是根据请求创建的。在这个StackOverflow 问题中了解更多信息
它对你的改变是在这段代码中
public class PersonController : Controller
{
List<PersonModel> people = new List<PersonModel>()
{
... adding instances ...
};
.... rest of your code ...
}
people
每个请求都会重新创建一个实例。并且您的代码在添加数据后people
使用此行向用户的浏览器发出 HTTP 重定向
return RedirectToAction("Index");
从服务器的角度来看,请求到此结束,后续获取List
页面的请求是单独的请求。没有新添加的人,people
重新创建列表意味着什么。
有一个非常简单的修复方法,但影响并不那么简单。
像这样添加static
关键字。
static List<PersonModel> people = new List<PersonModel>() { ... };
现在这个列表将成为类的静态成员 - 不与给定实例相关联,而是与类本身相关联。你可以在这里阅读更多关于什么是静态的。您应该仔细阅读静态成员部分。
这不简单的含义是什么?
添加后,您的代码变得不是线程安全的。为什么?想象一下两个请求同时发生,或者两个请求非常接近,两个不同的PersonModel
. 根据List<T>
C# 中的实现(它本身是否是线程安全的),您最终可能会遇到不同的情况:
- 两个人都被添加了。欢呼!
- 只添加了一个人。这怎么可能?假设将元素添加到列表程序需要在实际添加此人之前解析在哪个索引处添加新人。在这两个事件之间的短时间内,另一个请求(线程)可能想要做完全相同的事情。所以它解析了相同的索引(因为之前的线程还没有添加它的人)。所以第二个线程获胜,它的人会覆盖第一个人的人。
- 抛出一些异常。我不知道它是否会发生
List<T>
,但Dictionary<K, V>
如果同时访问,实际上有时会抛出异常。
如何避免新问题?
如果这是您的学习项目,您最好什么也不做,因为这可能永远不会发生。
但是,如果您想学习或者这不是要扔掉的东西,您可能想用它lock
来让线程在之前完成添加之前等待。
将此添加为您的类中的一个字段(注意静态关键字):
private static object _lock = new object()
并像这样添加到列表中:
lock(_lock) {
people.Add(per);
}
另一种选择是使用线程安全集合而不是List<T>
like ConcurrentBag<T>
。你可以在这里阅读更多关于它们的信息。
推荐阅读
- pytorch - 多 GPU PyTorch
- python - 应用函数未正确循环数据框中的列表
- flutter - Flutter Plugin - 无法解析方法'startActivityForResult'
- python - Airflow 中的 Joblib 和其他并行任务
- netsuite - 执行完成项目时删除工具包中的文章行
- google-chrome-extension - 从 Chrome 扩展播放音频时,如何隐藏/更改在 Chrome 全局媒体控件中显示的站点标题?
- python - 使用 NumPy 从原始数组计算带有位掩码的新数组(用于优化)
- sql - 如何在 PostgreSQL 中迭代使用 INSERT INTO
- typescript - 在 Sinon 中,无法成功 stub/mock 方法返回
- apache-kafka - 适用于 AWS MSK 的 Java 生产者