在Web开发中,经常需要将数据从一个页面提交到另一个页面。本文将介绍如何在ASP.NET MVC框架中实现这一功能,特别是如何将一个JSON对象从一个控制器动作提交到另一个控制器动作,并实现页面跳转。
目标是从一个页面提交一个JSON对象到另一个页面,并在提交后跳转到目标页面。这个过程涉及到从一个控制器动作到另一个控制器动作的数据传递。
[HttpPost]
public ActionResult SubmitOrder(OrderViewModel vmOrder)
{
// 处理vmOrder
return View(vmOrder);
}
function CollectOrderDetails() {
var order = new Object();
// 填充订单数据
// 将订单对象序列化后提交到目标页面
JSON.stringify(order);
}
要实现提交操作(POST),有以下几种选择:
使用jQuery的.post或.ajax方法,并设置content-type为"application/json",可以将序列化的订单对象发送到目标控制器动作。ASP.NET MVC会自动将JSON对象反序列化为OrderViewModel。但问题在于,这是Ajax调用,响应会在Ajax的xhr对象中返回,因此不会发生页面跳转。
这种方法与前一种类似,区别在于当响应从xhr对象返回时(在这种情况下,响应是一个代表目标页面的完整HTML响应),将其注入到文档中。这种方法的问题在于,它会返回HTML和JavaScript,但不会被解析,仍然停留在源页面(URL将保持不变),并且只显示了目标页面。这种方法最适合处理部分视图,或者处理返回静态内容且不包含需要解析的脚本标签的页面。
这种方法是创建一个表单元素,在JavaScript中创建一个隐藏的HTML input元素,将订单对象序列化并存储在隐藏字段中,将隐藏的input元素附加到表单并提交。
var form = document.createElement("form");
var input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", "XOrder");
input.setAttribute("value", JSON.stringify(order));
form.appendChild(input);
document.body.appendChild(form);
form.submit();
希望实现的是不使用Ajax的正常表单提交(POST),并希望控制器动作的参数自动反序列化为视图模型参数(OrderViewModel)。为了实现这一点,需要更深入地了解ASP.NET MVC中的模型绑定器,模型绑定器负责将传入MVC控制器的HTTP请求转换为控制器可以理解和处理的对象。
public class JsonModelBinder : DefaultModelBinder
{
public override BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
try
{
var strJson = controllerContext.HttpContext.Request.Form[bindingContext.ModelName];
if (string.IsNullOrEmpty(strJson))
{
return null;
}
else
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
var model = serializer.Deserialize(strJson, bindingContext.ModelType);
var modelMetaData = ModelMetadataProviders.Current.GetMetadataForType(() => model, bindingContext.ModelType);
var validator = ModelValidator.GetModelValidator(modelMetaData, controllerContext);
var validationResult = validator.Validate(null);
foreach (var item in validationResult)
{
bindingContext.ModelState.AddModelError(item.MemberName, item.Message);
}
return model;
}
}
catch (Exception ex)
{
bindingContext.ModelState.AddModelError(bindingContext.ModelType.Name, ex.Message);
}
}
}
首先,将JsonBinder属性添加到目标控制器动作的参数上:
[HttpPost]
public ActionResult SubmitOrder([JsonBinder] OrderViewModel vmOrder)
{
// 处理vmOrder
return View(vmOrder);
}
其次,当从JavaScript发送数据时,将隐藏字段的名称设置为参数的名称:
var form = document.createElement("form");
var input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", "vmOrder");
input.setAttribute("value", JSON.stringify(order));
form.appendChild(input);
document.body.appendChild(form);
form.submit();