如何在模型验证失败时正确保存视图渲染数据? [英] How to properly preserve view rendering data on model validation failure?

查看:119
本文介绍了如何在模型验证失败时正确保存视图渲染数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我有一个表格,用户可以在其中向其帐户添加银行帐户.我已经通过控制器上的两个操作实现了这一点,即:

In my application, I have a form where a user can add a bank account to their account. I've implemented this through two actions on my controller, namely:

public async Task<IActionResult> Add()
{
    var client = await _clientFactory.CreateClientAsync();

    // We obtain the available account types from a remote service.
    var accountTypes = await client.GetAccountTypesAsync();

    var viewModel = new AddAccountViewModel
    {
        AccountTypes = accountTypes;
    }

    return View(viewModel);
}

[HttpPost]
public async Task<IActionResult> Add(AddAccountViewModel model)
{
    if (!ModelState.IsValid)
        return View(model);

    // Store the account for the user, and redirect to a result page.
}

我的AddAccountModel当前看起来像这样,有两个目的:

My AddAccountModel currently looks like this, and has two purposes:

public class AddAccountViewModel
{
    public List<AccountTypeModel> AccountTypes { get; set; }

    [Required]
    [StringLength(100)]
    public string AccountName { get; set; }

    [Required]
    [Range(1, int.MaxValue]
    public decimal CurrentBalance { get; set; }

    [Required]
    public Guid AccountTypeId { get; set; }
}

一方面,AccountTypes属性用于填充视图中的列表:

One the one hand, the AccountTypes property is used to populate a list in the view:

@{
    var accountTypeList = new SelectList(accountTypes, "Id", "Name");
}

<select class="form-control" id="accountType" asp-for="AccountTypeId" asp-items="@accountTypeList">

</select>

当我通过GET /Add到达初始页面时,这一切都很好.表单呈现后,正如我期望的那样,选择框将填充服务中的项目.

This all works fine when I arrive on the initial page via GET /Add. The form renders, the select box is populated with the items from the service, as I'd expect.

但是,该表单还包含验证,并且如果用户输入无效数据或将字段留空,则会调用POST /Add,传递模型,运行验证,并最终将用户重定向到GET /Add,具体取决于验证失败的原因.这就是问题所在.

However, the form also includes validation, and should a user input invalid data or leave fields empty, POST /Add is called, passed the model, runs validation, and ultimately redirects the user back to GET /Add, with the specific reasons as to why validation failed. This is where the problem arises.

当用户被重定向回表单并要求更正其输入时,我的模型中的AccountTypesnull.这很有意义,因为我们没有将它作为POST请求的一部分发送-它仅用作要呈现的表单的输入.在表单不知道帐户类型的情况下,用户将永远无法更正其输入,因为他们将无法选择有效的帐户类型.

When the user is redirected back to the form and asked to correct their input, AccountTypes in my model is null. Which makes sense, as we didn't send it as a part of the POST request - it only serves as input for the form to render. With the form not knowing the account types, the user will never be able to correct their input, as they won't be able to select a valid account type.

如上所述,我的模型有两个方面:一方面,它包含视图需要呈现的数据,另一方面,它包含用户提供的数据,然后由应用程序进行处理.

As mentioned above, my model is two-fold: on the one hand it contains data the view requires to render, and on the other hand it contains data the user provides and is then processed by the application.

鉴于上述情况,我的问题是:当模型验证失败时,如何正确保存视图呈现所需的输入数据?也就是说,我的ViewModel是保存AccountTypeModel的集合的正确位置,还是应该将它们保存在ViewData甚至是TempData中?

Given the above, my question is: how should I properly preserve the input data required for my view to render when model validation failed? I.e., is my ViewModel the correct place to keep the collection of AccountTypeModels, or should I be keeping them in ViewData, or perhaps even TempData?

当前,我的应用程序和服务都是无状态的,这就是为什么我还没有遵循只是将其固定在TempData中"的路线的原因,从我收集到的信息来看,TempData存储在服务器的会话中.如果可以避免的话,我也不想在视图开始时向服务查询可用的帐户类型,因为这似乎违反了MVC的关注点分离.

Currently, both my application and services are stateless, which is why I didn't go down the "just stick it in TempData" route yet, as from what I can gather, TempData is stored in the server's session. I also don't want to query the service for the available account types at the start of the view if I can avoid it, as it seems to violate MVC's separation of concerns.

感谢阅读,希望有人可以帮助我.

Thanks for reading, and I hope someone can help me out with this.

推荐答案

您需要在POST方法中重新填充AccountTypes集合,然后再返回视图.我建议您的视图模型包含属性public IEnumerable<SelectListItem> AccountTypes { get; set; }而不是List<AccountTypeModel>,以便您无需在视图中生成SelectList.

You need to repopulate the AccountTypes collection in the POST method before you return the view. I would recommend that your view model contain a property public IEnumerable<SelectListItem> AccountTypes { get; set; } rather than List<AccountTypeModel> so that you do not need to generate the SelectList in the view.

要使其保持干燥,请创建一个私有方法来配置您的视图模型

To keep it DRY, create a private method to configure your view model

public async Task<IActionResult> Add()
{
    var model = new AddAccountViewModel();
    ConfigureViewModel(model);
    return View(model);
}

[HttpPost]
public async Task<IActionResult> Add(AddAccountViewModel model)
{
    if (!ModelState.IsValid)
    {
        ConfigureViewModel(model);
        return View(model);
    }
    ....
}

private async Task ConfigureViewModel(AddAccountViewModel model)
{
    var client = await _clientFactory.CreateClientAsync();
    var accountTypes = await client.GetAccountTypesAsync();
    model.AccountTypes = new SelectList(accountTypes, "Id", "Name");
}

这篇关于如何在模型验证失败时正确保存视图渲染数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆