2012-11-09 28 views
5

我很新的MVC,并尝试将现有的网站移植到MVC4时遇到此问题。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); 
    } 

我试图用一个[email protected]( “指数”,型号),而不是下面的块中的按钮来调用控制器并执行重定向(重定向本身确实有效,但是之后我必须在控制器内执行另一个服务调用以检索与我从调用视图一起工作的相同文档),因为模型中的Document对象对c继续返回NULL ontroller。

以下是调用控制器并实际返回完整模型的视图部分:我认为我正在寻找的是一种无ajax的方法,以便我可以重定向到分发/索引页面(这是从分发/ 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,     
       });     
     }); 

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

+0

为什么你只需'返回RedirectToAction(“Index”,distributionModel);'作为'Distribution/DocumentDetails'行为的最后一行? – Suhas

+0

DocumentDetails操作返回DocumentDetails视图。另外,我尝试从一个控制器方法中做一个RedirectToAction,并发现它将Document对象作为NULL传递给其他操作。 – gutsmania

回答

7

我不确定我是否完全了解您的问题,但我可以告诉您,您需要将表格中的每个值都放在表单中发布到控制器操作的表单上,并且您希望而不是为空。

这是究竟是你在你的ajax调用中做了什么:你现在将整个模型转换为json并使用jQuery能力再次转换它以发布数据。假设你有例如以下模型:

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

你的JavaScript代码将使用jQuery创建一个类似{ A: 'Value for a', B: 'Value for B' }将被转换成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设置为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]) 
} 

包含在回发的每个属性将不为空可能已被用户伪造,因为它们被简单地重新传输到服务器,假设它们被呈现在隐藏字段中,其为。事实上,您不能确定重新传输的值是您之前通过服务调用获取的值。

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

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(...); 
} 

两个变体都赞成和反政府,例如像一个浏览器会话或需要的类内的两个标签浏览可序列化时,他们可能是有问题的,当你正在使用会话状态服务器。尽管如此,过程都是一样的:你将不得不

  • 获取你需要从服务中的数据,每次(什么是昂贵的)或
  • 保存他们的任何地方服务器(TempData的,会话和东西上)或者
  • 用表单提交它们(可以由用户伪造,并不总是那么容易)。

选择你的毒药。 ;-)

+0

很好的解释! – TTT

相关问题