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;放; 公共异步任务 OnPostAsync() if (!ModelState.IsValid) return Page(); _db.Customers.Add(客户);等待_db.SaveChangesAsync(); Message = $"添加了客户 Customer.Name"; return RedirectToPage("./Index"); docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/…【参考方案4】:

您需要在代码中修复两件事:

首先,您需要使用 [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 方法

ASP.net MVC - 如何在各种视图中保留模型

推送视图控制器后如何保留 UITabBar

如何在 SWIFT 中更改 ViewController 后保留集合视图滚动位置

如何在保留 onClickListener 的同时将菜单按钮添加到列表视图?

移动子视图时,如何将其子视图保留在其父视图中的同一位置?