将Viewmodel传递给Controller是个好主意吗?

时间:2014-04-11 19:00:30

标签: c# asp.net-mvc model-binding

我对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 " />
}

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

3 个答案:

答案 0 :(得分:3)

  

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

这与ASP.Net MVC的设计方式完全相反。 ASP.Net附带了用于Bind data from a Form, Querystring, Ajax (Json and XML) to a strongly typed object for a Controller Method的默认ModelBinder。

  

我的问题是&#34;退款&#34;控制器中的对象始终从视图空到达。

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

  

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

我希望Ajax将RefundModel发回控制器以验证退款。如果它是有效的,那么动态创建表格中的字段,最终model bind back to an 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
         }
       }
     });
  });
});

答案 1 :(得分:1)

  

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

你有点不对劲。 ViewModel和Domain Model之间存在差异。 View Model是一个用于处理视图和域(业务)之间逻辑的类。

然后是Domain Model(在.net中)这通常是一些数据容器对象(PO​​CO)。这是贫血的。基于DDD有一点差异。

那么什么是最好的实践?

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

然后在控制器中,你可以使用mapper(automapper或valueinjecter)来转换它们。

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

答案 2 :(得分:0)

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

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

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