OnPost 后如何将模型保留在视图中?
Posted
技术标签:
【中文标题】OnPost 后如何将模型保留在视图中?【英文标题】:How can I keep my model in my View after OnPost? 【发布时间】:2018-10-13 19:02:26 【问题描述】:我正在使用 .Net Core 进行项目,并且正在使用 ASP Razor Pages。 在我的模型中,我有一个 OnGet,它可以在我的视图中加载我需要的所有数据。
public IList<Projet> Projets get; set;
public ActionResult OnGet()
Projets = _serviceSelect.getProjets();
return Page();
然后,在我提交表单时激活的 OnPost 中。
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input type="radio" value="1" asp-for="LoginData.TypeCompte" />choice<br />
Username: <input asp-for="LoginData.Username" /><br />
Password: <input asp-for="LoginData.Password" /><br />
Remember me: <input asp-for="LoginData.RememberMe" type="checkbox" /><br />
<input asp-page-handler="connexion" type="submit" value="Login" />
@html.AntiForgeryToken()
</form>
我想使用我的 ModelState 在我的视图中显示一个错误。
public ActionResult OnPostConnexion()
if (ModelState.IsValid)
// Do stuff
else
ModelState.AddModelError("", "username or password is blank");
return Page();
但是,当我返回 Page() 时,就像重新加载模型一样,当我尝试访问我的数据时,我的对象为空。
Object reference not set to an instance of an object.
@foreach (var item in Model.Projets)
如何在不丢失模型中包含的数据的情况下更新视图?
【问题讨论】:
【参考方案1】:我通过在public ActionResult OnPostConnexion()
中将return Page();
替换为return this.OnGet();
解决了这个问题
这样,您在 OnGet 中填充 PageModel 属性的任何逻辑都会被重用。
所以我的完整示例如下所示:
public IEnumerable<SelectListItem> CompanyListing get; private set;
public async Task<IActionResult> OnGet()
if (!string.IsNullOrEmpty(this.ErrorMessage))
this.ModelState.AddModelError(string.Empty, this.ErrorMessage);
this.CompanyListing = await this.PopulateCompanyList();
return this.Page();
public async Task<IActionResult> OnPostAsync()
if (!this.ModelState.IsValid)
// Something failed. Redisplay the form.
return await this.OnGet();
return this.RedirectToPage("/");
【讨论】:
【参考方案2】:您收到对象引用错误的原因是返回视图时尚未填充 Model.Projects,因此无法在 foreach 循环中进行迭代。
根据您现有的代码,您可以在返回页面之前再次填充您的模型。
public ActionResult OnPostConnexion()
if (ModelState.IsValid)
// Do stuff
else
Projets = _serviceSelect.getProjets();
ModelState.AddModelError("", "username or password is blank");
return Page();
更好的解决方案是:
public ActionResult OnPostConnexion(viewModel model)
if (!ModelState.IsValid)
return View(model);
else
//do stuff
【讨论】:
是的,我曾想过这样做,但不能简单地保持模型不变吗?或者asp总是在一个方法之后重新加载模型? 你应该返回 View("ViewName", model) 因为是 Razor pages 项目,无法返回 "View()"【参考方案3】:当您调用“Page()”时,这是在请求一个新的 Page 对象,当您返回该对象时,它将是空白的。页面和视图是不同的,通常使用 ASP 您将使用视图,MSDN 上有一些关于差异以及为什么的好文章,但现在只要将 Page() 更改为 View() 应该可以解决问题。
【讨论】:
我假设这是一个 MVC 项目 我不能“返回 View()”,因为这是一个 Razor 页面项目 [TempData] public string Message get;放; 公共异步任务您需要在代码中修复两件事:
首先,您需要使用 [BindProperty] 标记您的 Projets 属性,如下所示:
[BindProperty]
public IList<Projet> Projets get; set;
然后您需要重新编码您的页面,以便 Projet 的字段位于 form
标记内,以便将它们发布回页面,然后您需要重写输出它们的方式:
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input type="radio" value="1" asp-for="LoginData.TypeCompte" />choice<br />
Username: <input asp-for="LoginData.Username" /><br />
Password: <input asp-for="LoginData.Password" /><br />
Remember me: <input asp-for="LoginData.RememberMe" type="checkbox" /><br />
<input asp-page-handler="connexion" type="submit" value="Login" />
@Html.AntiForgeryToken()
<!-- SEE REMARK BELOW! -->
@
for (int i = 0; i < Model.Projets.Count; i++)
<input asp-for="@Model.Projets[i].FieldOne" />
<br />
<input asp-for="@Model.Projets[i].FieldTwo" />
</form>
备注 您需要在列表中呈现您的字段,以便它们获得唯一的 ID,以便 ModelBinder 可以在 Post 上检索它们。在我的例子中,我将一个字段命名为 FieldOne,这就是它的呈现方式:
<input type="text" id="Projets_0__FieldTwo" name="Projets[0].FieldTwo" value="one">
【讨论】:
使用你的提案和@j9070749的解决方案有区别吗?因为如果我这样做,我只是再次填充我的模型,但在视图中? 以我的方式,您只需将数据从 html 发布回 Page,无需像 @j9070749 答案那样查询您的数据库。【参考方案5】:我遇到了同样的问题,建议的解决方案中没有人工作。 我通过简单地使用帮助类为我保留模型来解决它。 该解决方案并不优雅但有效:)
public interface ISessionHelper
void AddRenewItem(string key, object item);
object GetItem(string key);
public class SessionHelper : ISessionHelper
private readonly Dictionary<string, object> _sessionBag;
public SessionHelper()
_sessionBag = new Dictionary<string, object>();
public void AddRenewItem(string key, object item)
if (_sessionBag.Keys.Contains(key)) _sessionBag.Remove(key);
_sessionBag.Add(key, item);
public object GetItem(string key)
if (_sessionBag.Keys.Contains(key))
return _sessionBag[key];
return null;
在我的 get 方法中,我将一个项目添加到字典中:
public async Task<IActionResult> OnGetAsync(int? id)
...
_sessionHelper.AddRenewItem(this.ToString(), this);
...
在我的 post 方法中,我从字典中取回模型并为当前模型分配所需的属性:
public async Task<IActionResult> OnPostApplyGuess(int itemId)
GameModel model = (GameModel) _sessionHelper.GetItem(this.ToString());
MyProp1= model.MyProp1;
MyProp2 = model.MyProp2 ;
MyProp3= model.MyProp3;
if (!ModelState.IsValid)
return Page();
return Page();
不要忘记将服务添加为单例:
services.AddSingleton<ISessionHelper, SessionHelper>();
我希望它对某人有所帮助:)
【讨论】:
【参考方案6】:尝试使用 TempData。
更多信息:http://www.tutorialsteacher.com/mvc/tempdata-in-asp.net-mvc
【讨论】:
以上是关于OnPost 后如何将模型保留在视图中?的主要内容,如果未能解决你的问题,请参考以下文章
Razor View 将错误的 Id 传递给 OnPost 方法
如何在 SWIFT 中更改 ViewController 后保留集合视图滚动位置