将Viewmodel传递给Controller是个好主意

本文关键字:好主意 Controller Viewmodel | 更新日期: 2023-09-27 17:58:01

我对MVC还很陌生,有一个关于我正在创建的表单的问题。页面顶部有一个表单,底部有一个网格。当人们在表单中输入数据并单击按钮时,表单数据将添加到下面的网格中。

我的计划是使用BeginForm并将表单发送到HttpPost控制器方法进行处理,然后返回到视图。目前,我正在使用这个视图上的表单:

@using (Html.BeginForm("AddRefund", "Refund", FormMethod.Post))

在控制器中,我有这个:

[HttpPost]
public ActionResult AddRefund(RefundModel refund)  
{
   if (ModelState.IsValid)
   {
       (etc...)

我的问题是,控制器中的"退款"对象总是从视图空到达。从我的研究来看,控制器中的模型参考似乎只是为了提供模型结构,而不是从视图中接收实际模型。然而,我不明白为什么会这样,因为能够将填充的视图模型从视图发送到控制器似乎非常有价值。

另外,你们将如何处理这个问题的代码?如何从用户那里收集所有这些表单提交,在表单下方的网格中向用户呈现,然后最终提交页面并将网格中的所有项目插入数据库?


编辑:这是我的看法

@model RefundsProject.Models.RefundModel
@using (Html.BeginForm("AddRefund", "Refund", FormMethod.Post))
{
    (all of the form elements are here)
    <input id="button-add" type="submit" value=" Add Refund to List " />
}

最终,在视图的最底部会有另一个按钮,它会将用户在网格中输入的所有项目提交到数据库。

将Viewmodel传递给Controller是个好主意

从我的研究来看,控制器中的模型参考似乎只是为了提供模型结构,而不是从视图中接收实际模型。

这与ASP.NETMVC的设计方式完全相反。ASP.Net附带了默认的ModelBinder,用于将Form、Querystring、Ajax(Json和XML)中的数据绑定到Controller方法的强类型对象。

我的问题是,控制器中的"退款"对象总是从视图空到达。

这很可能是由于缺乏知识或对模型绑定器工作方式的误解。

另外,你们将如何处理这个问题的代码?

我会Ajax将RefundModel发布回控制器以验证退款。如果它是有效的,那么在表单中动态创建字段,该字段最终将在新方法上建模绑定回IEnumerable/List,然后一次一个地验证所有退款(以再次验证数据)。

下面是一个非常分解的例子(可能需要一些工作,但重要的部分已经存在):

类别:

public class AddRefundsViewModel
{
  public RefundModel Refund { get; set; }
}
public class RefundModel
{
  public string Reason { get; set; }
  public Decimal Amount { get; set; }
}

方法:

public ActionResult AddRefunds()
{
  var model = new AddRefundsViewModel()
  model.Refund = new RefundModel();
  return this.View(model);
}
[HttpPost]
public ActionResult ValidateRefund(AddRefundsViewModel model)
{
  var result = new { isValid = modelState.IsValid };
  return this.Json(result);
}
[HttpPost]
public ActionResult ValidateRefunds(IEnumerable<RefundModel> model)
{
  var isRefundsValid = true;
  foreach (var refund in model)
  {
    isRefundsValid = TryValidateModel(refund);
    if (!isRefundsValid )
      break;
  }      
  if (isRefundsValid)
  {
  }
  else
  {
    // either someone hacked the form or
    // logic for refunds changed.
  }
}

视图:

@model AddRefundsViewModel
// assuming RefundController
@using (Html.BeginForm("Refund", "ValidateRefunds", FormMethod.Post))
{
  @html.EditFor(m => m.Refund.Reason)
  @html.EditFor(m => m.Refund.Amount)
  <input type="button" id="addRefundButton" name="addRefundButton" value="add"/>
  <input type="submit" id="submitRefundButton" name="submitRefundButton" value="submit all"/>
}
<!-- jquery -->
$(document).ready(function()
{
  $('#addRefundButton').on('click', function()
  {
     $.ajax({
       url: '/Refund/ValidateRefund',
       data: $("addRefundForm").serialize(),
       success: function(result)
       {
         if (result.isValid)
         {
           // create new hidden imput elements, and grid
           $("addRefundForm")[0].reset();
         }
         else
         {
           // Refund isn't valid
         }
       }
     });
  });
});

从我的研究来看,控制器中的模型参考似乎只是为了提供模型结构,而不是从视图中接收实际模型。然而,我不明白为什么会这样,因为能够将填充的视图模型从视图发送到控制器似乎非常有价值。

你有点错了。ViewModel和Domain Model之间存在差异。视图模型是一个类,用于处理视图和域(业务)之间的逻辑。

然后是域模型(在.net中),它通常是一些数据容器对象(POCO)。这是贫血。根据DDD有一点不同。

那么,什么是最佳实践呢?

使用ViewModel对象在视图和控制器之间传输数据总是很好的。

然后在控制器中,您可以使用映射器(自动映射器或值注入器)来转换它们。

现在您有了可以处理的域对象。

使用ViewModels在控制器和视图之间上下传递数据是完全可以接受的。

为了帮助您的模型出现空问题,输入(如<input id="FirstName" type="text" />)需要具有MVC模型绑定器的名称属性,以将您发布的内容映射到RefundModel对象中。在您共享的视图代码中,您只显示了一个提交按钮,因此尚不清楚您希望映射的其他元素是否有名称。

要修复我上面的输入标记示例,您需要执行<input id="FirstName" name="FirstName" type="text" />或使用Razor助手:@Html.TextBoxFor(m => m.FirstName)