2010-06-20 74 views
9

這可能又是一個新手問題。ASP.Net MVC部分視圖保持其模型狀態?

當我創建一個ASP.NET MVC2應用程序,有動作登錄的賬號控制器創建這樣的:

[HttpPost] 
public ActionResult LogOn(LogOnModel model, string returnUrl) 
{ 
    if (ModelState.IsValid) 
    { 
     if (MembershipService.ValidateUser(model.UserName, model.Password)) 
     { 
     FormsService.SignIn(model.UserName, model.RememberMe); 
     if (!String.IsNullOrEmpty(returnUrl)) 
     { 
      return Redirect(returnUrl); 
     } 
     else 
     { 
      return RedirectToAction("Index", "Home"); 
     } 
     } 
     else 
     { 
      ModelState.AddModelError("", "The user name or password provided is incorrect."); 
     } 
    } 

     // If we got this far, something failed, redisplay form 
     return View(model); 
    } 

現在,我不希望有一個登錄頁面,我想有登錄控件作爲更大頁面的一部分。所以,我將Login.aspx更改爲Login.ascx,並將其與Html.RenderPartial或Html.RenderAction集成到我的主視圖中。

如果登錄成功,兩者都很有魅力。如果不是,

return View(model) 

正在殺死我。 我想要的是返回到我的主頁(稱爲Home/Index),但帶有局部視圖的錯誤信息。

return RedirectToAction("Index", "Home") 

顯然不起作用。

提示?

回答

3

這當然不是一個新手問題,我已經梳理了網絡上的這個問題的答案,到目前爲止我找到的最好的解決方案是隱藏在本教程here。這就是Darin Dimitrov提出的Ajax刷新建議。我來總結一下該鏈接的重要組成部分,爲什麼這是不容易固定:/

阿賈克斯刷新基於怪異情人

以下功能與阿賈克斯刷新幾乎鉸鏈解決方案(奇怪的情人使用ControllerContext,但它並沒有爲我存在,所以我有ControllerExtension):

ControllerExtension.RenderPartialViewToString(this,"mypartial", (object)model) 

這個功能就是把你的模型+的ModelState和重新渲染您的局部視圖到HTML字符串。然後,您可以獲取該字符串,然後將其發送回json對象,以便刷新視圖。我用jQuery和它看起來像這樣,

$(document).ready(function() { 
    var partialViewUpdate = function (e) { 
      e.preventDefault(); //no postback 
      var partialDiv = $(this).parent(".partial"); 
      $.post($(this).attr("action"), 
        $(this).serialize(), 
        function (json) { 
        if (json.StatusCode != 0) { 
         // invalid model, return partial 
         partialDiv.replaceWith(json.Content); 
        } 
        else if (json.Content != null && json.Content != "") { 
         window.location.replace(data.Content); 
        }; 
      }); 

    $(".partial").find("form") 
       .unbind('submit') 
       .live("submit", partialViewUpdate); 
}; 

jQuery的解釋:

  1. 查找包含我的部分(類= 「局部」)div和發現窗體中該div
  2. 解除任何其他「提交」事件的形式(我得到了一些奇怪的雙提交錯誤,直到我做了解綁)。
  3. 使用的「活」,這樣一旦內容被替換它再重新綁定
  4. 一旦我們進入功能partialViewUpdate ...
  5. 防止從完成提交,以便它可以全部由AJAX來處理的形式。
  6. 獲取包含DIV我的部分(將使用這個版本)
  7. 設置jQuery的URL後從形式服用,$(本).attr(「行動」)
  8. 採取的形式(即我們的模型)並將其序列化爲控制器函數$(this).serialize()
  9. 創建將處理ajax返回值的函數。
  10. 我使用我自己的個人json對象,其中StatusCode 1是壞的。所以,如果它不好,我拿什麼在內容中,這是RenderPartialViewToString給了我的字符串,我只是替換包含我的部分的div的內容。

爲什麼它不「只是工作」正常

因此諧音不只是ModelState中驗證工作的原因是,你不能用POST返回查看(模型)因爲MVC會將其解析爲部分視圖(login.ascx)的路由地址,而不是部分嵌入的位置(index.aspx)。

您也不能使用RedirectAction(),因爲它會將它發送到(index.aspx)控制器函數,這相當於清除所有內容並刷新index.aspx頁面。但是,如果您使用Chino和Thabaza建議的ActionFilter,那麼當您的頁面刷新並且login.ascx控制器函數再次被觸發時,它將拾取該tempdata。但是,如果刷新頁面會導致客戶端代碼(如彈出窗口模式)的麻煩(即,如果刷新彈出窗口消失),則此操作不起作用。

說它不是那麼

我寧願如果它「只是工作」,因此,如果有人知道這樣做pleaaaase份額它的正確/更好的辦法!我仍然認爲Ajax刷新和ActionFilter解決方案並不是一種乾淨的方式,因爲它幾乎使它看起來像部分視圖,如果沒有某種「技巧」,表單就無法使用。

1

呀redirecttoaction而是提供到TempData與它的錯誤信息,所以你應該做這樣的事情

TempData["errorMsg"] = "incorrect values provided"; 
return RedirectToAction("Index", "Home") 

當然,在主要指數,你應該有一個顯示該消息的DIV

<%= html.Encode(TempData["errorMsg"]) %> 

編輯 我看到你想維護可能是問題的模型狀態,但你可以做的是在索引操作中傳遞模型狀態或在tempdata中傳遞模型狀態對象。然後你可以做的是檢查對象中是否存在模型狀態錯誤,以及是否檢查該字段並將錯誤添加到右側字段。

+0

嗯,可能我可以把整個LogOnModel放在TempData中。但對我來說,這似乎是一個黑客。這裏乾淨的解決方案是什麼? – Sparhawk 2010-06-21 06:08:21

+0

是的,這是一個乾淨的解決方案是爲它寫一個過濾器。看看這個問題和我的答案舉例 http://stackoverflow.com/questions/2503032/where-to-use-controller-httpcontext/2503085#2503085 在過濾器中,您檢查模型狀態是否有效,如果不是添加值當然最好把它放在一個自定義屬性中,因爲我不認爲你需要在控制器的所有操作中使用這個值。然後,您可以在要維護模型狀態的操作上使用該屬性。 – Chino 2010-06-24 22:57:47

+0

呃。這是TempData的用途。我的猜測是你不喜歡魔法字符串和缺乏強類型的數據。這很公平,但它是一種風格選擇,而不是黑客。 – a7drew 2010-06-29 23:05:03

0

你可以明確地指定視圖返回:

return View("~/Views/Home/Index.aspx", model); 

這樣的錯誤信息將被保留,而正確地呈現。

+0

如果我這樣做了,我會將LogOnModel傳遞給Home/Index-View。這可能不會起作用。也許這個問題畢竟不是新手:) – Sparhawk 2010-06-21 06:05:38

+1

@Sparhawk,你是對的。如果您返回Home/Index視圖的模型會怎麼樣? LogOn視圖模型應該是Home/Index視圖模型的子集。作爲替代方案,您可以對LogOn表單進行Ajax化並異步調用此操作,以便在客戶機上執行重定向(window.location.href),並且在發生錯誤時它將返回一個「PartialView」和腳本調用這個動作會刷新包含這個表單的'div'。 – 2010-06-21 06:20:32

+1

目前它不是家庭/索引視圖模型的子集。我有一個門戶,每個頁面(如Home/Index)都有一些控件。我使用RenderAction將控件渲染到頁面中。那麼,爲什麼Home/Index現在應該查看有關LogonModel的任何內容? 當然,我可以使用ajax。但是這會讓人想起繞過這個問題。有驗證邏輯的部分視圖沒有乾淨的解決方案嗎? – Sparhawk 2010-06-21 09:56:38

0

看看這個blog的練習#13。當您使用PRG(Post-Redirect-Get)風格進行編碼時,此方法可以很好地傳遞模型狀態信息。您只需要創建幾個操作篩選器,並根據需要將它們應用於獲取和發佈操作。

0

我在使用Ajax.BeginForm時遇到了同樣的問題,我需要返回一個局部視圖,但是所有的模型狀態錯誤都消失了。 訣竅是將Ajax.BeginForm部件隔離到一個單獨的視圖中,並將RenderPartial視圖中的UpdateTargetId div另一個包含視圖。

通過這種方式,您可以返回帶有模型錯誤的視圖模型,或者只顯示您選擇的某個成功消息(如果有)。 這裏是一個很好的,詳細的解釋: http://xhalent.wordpress.com/2011/02/05/using-unobtrusive-ajax-forms-in-asp-net-mvc3/