现在,我们已经实现了支持HTTP-GET的Edit action方法。当用户请求/Dinners/Edit/2 地址时,接收一个HTML页面。点击Save保存按钮,将触发表单提交到/Dinners/Edit/2 网址,并通过HTTP POST提交<input> 表单中的值。下面,我们开始实现HTTP POST的Edit action 方法 – 负责处理保存操作。
通过添加一个重载的Edit action 方法到DinnersController类中,并设置AcceptVerbs属性,表示该方法负责处理HTTP POST动作。
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
publicActionResult Edit(int id,FormCollection formValues) {
}
当对重载的action 方法添加[AcceptVerbs] 属性后,ASP.NET MVC根据进来的HTTP动作,自动分发请求给合适的action方法。HTTP POST 请求/Dinners/Edit/[id] 将有上述Edit方法负责处理,然而所有其他的HTTP 请求/Dinners/Edit/[id] 将有之前定义的Edit方法负责(该方法没有[AcceptVerbs]属性)。
获取表单提交的值
在HTTP POST的Edit方法中,有很多方法可以获取表单参数值。一个简单的办法是使用Controller基类的Request属性来访问form集合,并直接获取提交的参数值:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
publicActionResult Edit(int id,FormCollection formValues)
{
// Retrieve existing dinner
Dinner dinner = dinnerRepository.GetDinner(id);
// Update dinner with form posted values
dinner.Title = Request.Form["Title"];
dinner.Description = Request.Form["Description"];
dinner.EventDate = DateTime.Parse(Request.Form["EventDate"]);
dinner.Address = Request.Form["Address"];
dinner.Country = Request.Form["Country"];
dinner.ContactPhone = Request.Form["ContactPhone"];
// Persist changes back to database
dinnerRepository.Save();
// Perform HTTP redirect to details page for the saved Dinner
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
上述方法有一点繁琐,特别是增加异常处理逻辑之后。
一个更好的方法是使用Controller 基类的内置方法UpdateModel()。该方法支持使用传入的表单参数更新对象的属性,它使用反射机制来解析对象的属性名称,接着基于客户端传入的参数值自动赋值给对象相关属性。
下面,我们使用UpdateModel() 方法来实现之前的HTTP-POST Edit Action 方法:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
publicActionResult Edit(int id,FormCollection formValues)
{
// Retrieve existing dinner
Dinner dinner = dinnerRepository.GetDinner(id);
UpdateModel(dinner);
// Persist changes back to database
dinnerRepository.Save();
// Perform HTTP redirect to details page for the saved Dinner
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
再次方法/Dinners/Edit/2 网址,并更改Dinner的标题和事件日期:
点击Save保存按钮,执行表单提交,触发Edit方法的调用,并将更新的值持久化到数据库。接着,重定向到详细页面 – Details视图(显示最新保存的数据)。
处理编辑异常
当前HTTP-POST实现方法工作正常 – 当然也会出现异常。当用户在编辑表单时犯错误了,我们需要确保表单显示错误信息,指导用户去纠正。这包括用户提交了错误的数据(如错误的日期格式),或者存在业务规则冲突等等。当发生错误是,表单需要保持用户初始录入的数据,这样他们不必重复录入一遍。这个过程需要重复多次,直到最终成功提交表单。
ASP.NET MVC 包括一些友好的内置功能,使异常处理和重新显示表单更容易。为了演示这些功能,下面我们再次更新Edit Action 方法,代码如下:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
publicActionResult Edit(int id,FormCollection formValues)
{
Dinner dinner = dinnerRepository.GetDinner(id);
try
{
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
catch
{
foreach (var issue in dinner.GetRuleViolations())
{
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View(dinner);
}
}
上述代码与之前的实现基本一致,除了增加了一个try/catch 异常捕获代码块。如果调用UpdateModel() 方法出现异常,或者保存DinnerRepository 时出现异常(如果我们试图保存一个无效的对象-规则冲突,将抛出异常),异常捕获代码块将触发执行。在catch代码块中,首先遍历Dinner对象中所有规则冲突,并添加到ModelState对象中,接着重新显示视图。
下面为了模拟异常信息,重新运行应用程序,编辑Dinner,并将Title清空,事件日期EventDate设置为ENTLIB,电话格式等等,然后点击Save保存按钮,现在HTTP POST触发Edit方法,但不能成功保存Dinner信息(因为有异常么),并重新显示表单:
现在,应用程序有更好的异常处理机制。有无效输入的文本框通过红色*进行提示,并且错误信息也显示在界面上。表单同时也保留了用户最初录入的信息 – 这样他们不必重复录入。所有这些是如何实现的呢?这是因为我们使用了一些内置的ASP.NET MVC功能,使输入验证和异常处理更加容易。