将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 " />
}
最终,在视图的最底部会有另一个按钮,它会将用户在网格中输入的所有项目提交到数据库。
从我的研究来看,控制器中的模型参考似乎只是为了提供模型结构,而不是从视图中接收实际模型。
这与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)