【问题标题】:How can I post a form content that is not related to a model?如何发布与模型无关的表单内容?
【发布时间】:2019-10-07 15:55:16
【问题描述】:

我有一个任务,我需要在一个表单中捕获三个值,提交它们,根据某些条件对这些值执行特定操作,这将引导我找到数据库行的索引,从数据库中获取一行使用计算出的索引,然后更新视图。

问题在于表单本身不是模型,也不会在表中创建实例/实体/行。当我创建视图时,我从 Razor 收到一个错误,说表达式树可能不包含动态操作,我知道这是因为表单与任何模型都不相关(因此我没有在.cshtml 文件)。我想我需要将内容发布到控制器并使用获取的值更新内容(我确实尝试使用提交按钮,但它会将我重定向到一个空页面,我知道这就是表单通常的功能,但这不是行为我需要)。

我尝试将 @model 指令添加到包含表单的 Index.cshtml 文件中,但由于我附加索引的模型不包含与我在表单中使用的相同的属性,因此 Razor 会抛出错误。我尝试为表单创建一个模型类,它以某种方式工作,我得到了所有值(它在提交时重定向,这不是我想要的)但我不相信这是正确的做法,因为表单本身不是用于在表中创建实体。

这是我将从数据库中获取值的模型:

using System;
using System.Collections.Generic;

namespace PrototipoExploratorio.Models
{
    public partial class Factores
    {
        public int FactorId { get; }
        public int ValorUno { get; }
        public int ValorDos { get; }
        public int ValorTres { get; }
    }
}

这是表格,目前在文件夹 Views/Factores 中(如上图所示)

@{
    ViewData["Title"] = "Index";
}

<h2>Factores</h2>
<form method="post" asp-controller="FactoresForm" asp-action="ObtenerFactor">
    <div class="form-group">
        <label for="Estatura" class="control-label">Estatura en centímetros</label>
        <input asp-for="Estatura" name="estatura" type="number" id="estatura" placeholder="168, 190, 155...">
    </div>
    <div class="form-group">
        <label for="Edad" class="control-label">Edad</label>
        <input asp-for="Edad" name="edad" type="text" id="number" placeholder="15, 24, 50...">
    </div>
    <div class="form-group">
        <label for="Peso" class="control-label">Peso en kilogramos</label>
        <input asp-for="Peso" name="peso" type="number" id="peso" placeholder="80, 70.5, 55.40...">
    </div>
    <div class="form-group">
        <label for="EstadoCivil" class="control-label">Estado civil</label>
        <select id="EstadoCivil" asp-for="EstadoCivil" for="EstadoCivil" name="EstadoCivil">
            <option value="soltero">Soltero</option>
            <option value="casado">Casado</option>
        </select>
    </div>
    <div class="form-group">
        <div>
            <label class="control-label">Factor calculado: </label>
            <h6 id="FactorCalculado">{this is where I will update the value calculated from the values submitted here and the database row that I will fetch}</h6>
        </div>
        <div class="form-group">
            <button asp-controller="FactoresForm" asp-action="ObtenerFactor" class="btn btn-primary" type="submit">Obtener factor</button>
            <button asp-controller="FactoresForm" asp-action="LimpiarDatos" class="btn btn-primary" type="submit">Limpiar</button>
        </div>
    </div>
</form>

这是控制器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using PrototipoExploratorio.Models;

namespace PrototipoExploratorio.Controllers {
    public class FactoresForm : Controller {
        // GET: /<controller>/
        public IActionResult Index() {
            return View();
        }


        [HttpPost]
        [ValidateAntiForgeryToken]
        // I expect to reach this code on form submit
        // I know that right now this does not work given the explanation above
        public IActionResult ObtenerFactor() {
            Console.WriteLine("");
            return View("Index");
        }
    }
}

我希望提交表单,做一些业务逻辑操作来获取数据库行的索引(映射到 Factores 模型),从行中获取值并更新视图。

【问题讨论】:

    标签: c# asp.net-mvc asp.net-core razor


    【解决方案1】:

    问题在于表单本身不是模型,也不会在表中创建实例/实体/行

    您误解了 View Model 的作用。视图模型是一个 POCO(普通旧 CLR 对象),用于渲染 视图。它可以是任何简单的对象。一个实体通常称为Data Model,它表示数据表中的一行。

    我尝试为表单创建一个 Model 类,它以某种方式工作,我得到了值和所有内容(它在提交时重定向,这不是我想要的)但我不认为这是正确的做法,因为表单本身不是用于在表中创建实体。

    事实上,这是正确的方法。请记住:

    1. View Model 用于渲染视图。它与数据模型无关。
    2. DTO 用于传输数据。 DTO 不必共享相同类型的数据模型。
    3. 您可以根据需要定义您的自定义DTO/View Model

    如何解决

    1. 在这种情况下,您将渲染视图,然后将数据发布到控制器。为了避免混淆“模型”命名,让我们创建一个DTO 来保存数据。

      public class FactorDto
      {
          public int Estatura {get;set;}
          public int Edad {get;set;}
          public decimal Peso {get;set;}
          public string EstadoCivil {get;set;}
      }
      

      FactorDto 这个名字根本不重要。随意更改名称。

    2. 要使用此DTO 呈现表单视图,您可以在表单视图文件中添加@model 指令:

      @model FactorDto
      @{
          ViewData["Title"] = "Index";
      }
      
      <h2>Factores</h2>
      ...
      
    3. 最后,改变你的控制器如下接收浏览器发送的数据:

      [HttpPost] [验证AntiForgeryToken] public IActionResult ObtenerFactor(FactorDto dto) { // ... 现在你已经得到了数据 }

      现在应该可以正常工作了。


    如果您有一个复杂的视图模型MyComplexViewModel,您可以通过以下方式组合它们:

    ```csharp
    public class MyComplexViewModel
    {
        public FactorDto FactorDto{get;set;}
        public Abc Abc {get;set;}
        public string A {get;set;}
        // ... feel free to add other properties as you like
    }
    ```
    

    并将视图模型声明为MyComplexViewModel

    @model 我的复杂视图模型 ... 因素&l;/h2> ... asp-for="FactorDto.Estatura" name="estatura" type="number" id="estatura" placeholder="168, 190, 155..."> ...

    【讨论】:

      猜你喜欢
      • 2015-11-03
      • 1970-01-01
      • 2012-09-21
      • 1970-01-01
      • 2016-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多