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

gut*_*nia 5 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; }
}
Run Code Online (Sandbox Code Playgroud)

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

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

我尝试使用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,                 
              });                
         });
Run Code Online (Sandbox Code Playgroud)

谢谢,任何帮助将非常感谢.

Pei*_*eit 8

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

正是您在ajax调用中所做的:您当前将整个模型转换为json并使用jQuery功能将其再次转换为发布数据.假设您有以下模型,例如:

public class TestModel {
    public string A { get; set; }
    public string B { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您的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
Run Code Online (Sandbox Code Playgroud)

因此,Index将调用您的操作并将DefaultModelBinder值绑定到模型属性.这适用于整数类型,如整数,也适用于复杂类型,例如集合.在DefaultModelBinder处理这些类型的转变.

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

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

public class ComplexModel {
    public ComplexSubModel SubModel { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

这将导致一个新的实例,ComplexModelSubModel属性设置为一个新的实例,ComplexSubModel其属性StringList设置为System.Collection.Generic.List<string>包含三个字符串的新实例First entry,Second entryThird entry.

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

@using (Html.BeginForm()) {
    @Html.HiddenFor(m => m.SubModel.StringList[0])
    @Html.HiddenFor(m => m.SubModel.StringList[1])
    @Html.HiddenFor(m => m.SubModel.StringList[2])
}
Run Code Online (Sandbox Code Playgroud)

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

另一种可能性是将服务调用的结果保存在TempData-dictionary中,实际上将值存储在用户会话中,并在回发操作中重新读取它们时将其销毁,或者直接将值存储在会议:

public ActionResult Index() {
    // Do service calls

    #region Variant a
    TempData["ServiceResultA"] = foo;
    TempData["ServiceResultB"] = bar;
    #endregion

    #region Variant b
    Session["ServiceResultA"] = foo;
    Session["ServiceResultB"] = bar;
    #endregion

    var model = new DistributionModel();
    // Set properties and stuff

    return View("Index", model);
}

[HttpPost]
public ActionResult Index(DistributionModel model) {
    // Read "cached" service calls

    #region Variant a
    var foo = (TResultA)TempData["ServiceResultA"];
    var bar = (TResultB)TempData["ServiceResultB"];
    #endregion

    #region Variant b
    var foo = (TResultA)Session["ServiceResultA"];
    var bar = (TResultB)Session["ServiceResultB"];
    #endregion

    // Do stuff

    return RedirectToAction(...);
}
Run Code Online (Sandbox Code Playgroud)

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

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

选择你的毒药.;-)