2012-11-09 32 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

相關問題