MVC4将复杂对象从视图传递到控制器,新视图不呈现

时间:2012-11-09 16:36:34

标签: asp.net-mvc

我是MVC的新手,在尝试将现有网站移植到MVC4时遇到了这个问题。

我们使用的模型中大部分数据都是通过服务调用填充的,所以显然我们希望将调用保持在最低限度。问题是,当我尝试将模型传递回控制器时,模型中的复杂对象总是变为空。我已经能够使用ajax将数据保留在回调控制器上;但是,我需要操作来返回一个新视图,并且在操作完成后,视图的代码会执行,但是没有重定向(我认为这是ajax的重点,我认为我要求的是一个解决方案将以相同的方式持久保存数据但实际重定向。)

这是我的模特:

public class DistributionModel
{
    public string typeOfDistribution { get; set; }
    public Document document { get; set; }
    public string thumbnailUrl { get; set; }
    public MergeFieldModel mergeFields { get; set; }
}

public class MergeFieldModel
{
    public MergeFields documentMergeFields { get; set; }
}

以下是我正在使用的控制器操作:

        public ActionResult Index(DistributionModel distributionModel)
    {
        distributionModel.mergeFields = new MergeFieldModel() { documentMergeFields = MergeFieldsHelper.GetDocumentMergeFields(distributionModel.document.Id) };
        return View("Index", distributionModel);
    }

我尝试使用href =@Url.Action(“Index”,Model)而不是下面的块中的按钮来调用控制器并执行重定向(重定向本身确实有效,但我必须执行另一个控制器内的服务调用以检索与我在调用视图中使用的文档相同的文档)因为模型中的Document对象保持返回为控制器的NULL。

以下是调用控制器并实际返回完整模型的视图部分:我认为我正在寻找的是一种在没有ajax的情况下实现此目的的方法,以便我可以获得重定向到分发/索引页面(这是从Distribution / DocumentDetails页面触发的)

        <button id="EmailDistribution" data-corners="false" data-theme="a">EMAIL</button>

         $('#EmailDistribution').click(function () {
              var model = @Html.Raw(Json.Encode(Model));
              $.ajax({
              url: '@Url.Action("Index", "Distribution")',
              type: 'POST',
              contentType: 'application/json; charset=utf-8',
              data: JSON.stringify(model),     
              processData: false,                 
              });                
         });

谢谢,非常感谢任何帮助。

1 个答案:

答案 0 :(得分:8)

我不确定我是否完全理解您的问题,但我可以告诉您,您需要将模型的每个值都放在一个表单中,并将其发布到您想要的控制器操作为空。

这是完全你在ajax调用中所做的事情:你当前将整个模型转换为json并使用jQuery能力再次将其转换为发布数据。假设您有以下模型,例如:

public class TestModel {
    public string A { get; set; }
    public string B { get; set; }
}

您的javascript代码将创建一个类似于{ A: 'Value for a', B: 'Value for B' }的字符串,该字符串将使用jQuery转换为HTTP POST请求:

POST /Controller/Index HTTP/1.1
Host: demo.loc
User-Agent: Mozilla/5.0 whatever
Content-Type: application/x-www-form-urlencoded; charset=utf-8

A=Value+for+a&B=Value+for+B

因此,系统会调用Index操作,DefaultModelBinder会将值绑定到模型属性。这适用于整数类型,如整数,也适用于复杂类型,例如集合。 DefaultModelBinder处理这些类型的转换。

让我们来看一个更复杂的模型:

public class ComplexSubModel {
    public ICollection<string> StringList { get; set; }
}

public class ComplexModel {
    public ComplexSubModel SubModel { get; set; }
}

DefaultModelBinder也可以绑定模型:

POST /Controller/Index HTTP/1.1
Host: demo.loc
User-Agent: Mozilla/5.0 whatever
Content-Type: application/x-www-form-urlencoded; charset=utf-8

ComplexModel.SubModel.StringList[0]=First+entry&ComplexModel.SubModel.StringList[1]=Second+entry&ComplexModel.SubModel.StringList[2]=Third+entry

这将导致ComplexModel的新实例,其SubModel属性设置为ComplexSubModel的新实例,其属性StringList设置为{的新实例{1}}包含三个字符串System.Collection.Generic.List<string>First entrySecond entry

现在您需要做的是将模型属性渲染为隐藏字段,以便它们包含在回发中:

Third entry

回发中包含的每个属性都不会为null 但是可能是由用户伪造的,因为它们很简单地重新传输到服务器假设它们是在隐藏字段中呈现。实际上,您无法确定重新传输的值是您之前通过服务调用获取的值。

另一种可能性是将服务调用的结果保存在@using (Html.BeginForm()) { @Html.HiddenFor(m => m.SubModel.StringList[0]) @Html.HiddenFor(m => m.SubModel.StringList[1]) @Html.HiddenFor(m => m.SubModel.StringList[2]) } - 字典中,该字典实际上将值存储在用户会话中,并在回发操作中重新读取它们时立即销毁它们或者直接将值存储在会话中:

TempData

这两种变体都有优点和缺点,比如在一个浏览器会话中浏览两个选项卡时可能会出现问题,或者在使用会话状态服务器时需要将类序列化。然而,程序总是一样的:你要么必须

  • 每次从服务中获取数据(价格昂贵)或
  • 时获取数据
  • 将它们保存在服务器上的任何位置(TempData,Session和stuff)或者
  • 使用表单提交(可以由用户伪造,并不总是很容易)。

选择你的毒药。 ; - )