2010-03-15 92 views
13

似乎在Asp.Net中調用Html.RenderAction如果子動作的類型與父動作的類型不同,那麼MVC2應用程序可以更改頁面的MIME類型。Asp.Net MVC2 RenderAction更改頁面MIME類型?

下面的代碼(在MVC2 RTM中測試)對我來說似乎很明智,當調用Home/Index時,將返回application/json類型的結果。瀏覽器不會讓頁面變得混亂,而會詢問您是否要下載它。

我的問題:我錯過了什麼嗎?這是一個錯誤?如果是這樣,什麼是最好的解決方法?

控制器:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     ViewData[ "Message" ] = "Welcome to ASP.NET MVC!"; 

     return View(); 
    } 

    [ChildActionOnly] 
    public JsonResult States() 
    { 
     string[] states = new[] { "AK", "AL", "AR", "AZ", }; 

     return Json(states, JsonRequestBehavior.AllowGet); 
    } 
} 

觀點:

<h2><%= Html.Encode(ViewData["Message"]) %></h2> 
<p> 
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>. 
</p> 
<script> 
    var states = <% Html.RenderAction("States"); %>; 
</script> 

回答

8

這不是一個錯誤。 JsonResult類型應該將結果設置爲JSON,因爲這通常是您想要的。

你真的不想要一個JSON 結果在這裏,你想要一個JSON 字符串。那麼爲什麼不寫這些呢?

[NonAction] 
public string States() 
{ 
    string[] states = new[] { "AK", "AL", "AR", "AZ", }; 

    return new JavaScriptSerializer().Serialize(states); 
} 
+5

這將工作......它似乎並不像一個兒童動作應該能夠改變整個頁面的ContentType。 – 2010-03-15 15:52:04

+0

請注意,與Json方法不同,JavaScriptSerializer().Serialize不能正確序列化嵌入的引號。你需要這樣的: Func safeForJson =(s)=> { return s.NotNull()。Replace(「\」「,」\\\「」); }; – 2012-02-06 15:16:48

+0

對不起,NotNull方法是我的,但只是確保輸入字符串不爲空(natch)。 – 2012-02-06 15:17:29

3

這可以通過,明確強制MIME類型爲「回」到text/html解決:

return Json(states, "text/html", JsonRequestBehavior.AllowGet); 

它似乎並不像這應該是必要的,但。

+1

這並不能解決問題,因爲隱藏它。 'JsonResult'在這裏仍然改變'ContentType';它只是改變你的(當前!)期望它。 – 2010-03-15 16:03:12

+0

對我來說,它只是返回一個帶有Json結果的文本文件......它只是我還是這個垃圾難以置信的錯誤...誰寫的這個垃圾? – SoftwareSavant 2011-07-29 23:34:13

1

Craig Stuntz said內容類型應該改變。

更好的方法是使用AJAX調用該動作,然後將返回的對象分配給JavaScript代碼中的states變量。

+1

你可以建議一個場景,其中這個行爲(兒童動作改變頁面的ContentType)實際上是你想要發生的嗎? – 2010-03-15 16:19:08

+0

@加貝Moothart,我想不出你想要發生這種情況。但問題是,問題不是ContentType的變化。問題是在呈現** HTML **視圖時調用** Json ** Result操作。 JsonResult將請求對象的ContentType屬性設置爲「application/json」,就像它應該的那樣。但不幸的是,由於您從HTML視圖中調用了該視圖,因此原始響應的類型會發生變化。 – 2010-03-15 16:29:49

8

我想到這個錯誤。如果這是一個子女正在呈現的操作,爲什麼它會更改父級的操作響應? Html.Action會將其呈現爲一個字符串。我的解決方法是:

Html.ViewContext.HttpContext.Response.ContentType = "text/html"; 

調用Html.Action後。我想有人能寫一個包裝HTML輔助擴展,是這樣的:

var aux = Html.ViewContext.HttpContext.Response.ContentType; 
Html.Action(....); // or Html.RenderAction(...) 
Html.ViewContext.HttpContext.Response.ContentType = aux; 
4

你不會失去了一些東西(除非我太),我認爲這是一個錯誤。我在ASP.NET MVC3中遇到同樣的問題。

我們有一個控制器操作,它從簡單的內容管理系統返回內容。 CMS允許用戶定義返回的內容類型(例如text/plain或text/xml)。

控制器操作可以直接調用,也可以調用爲子操作以允許視圖包含內容託管元素。

如果使用內容類型「text/plain」創建了一段內容,並將其嵌入到ASP.NET MVC視圖中,則會覆蓋父級的內容類型,並且瀏覽器顯示HTML。

Gabe,我認爲你已經打了個頭,因爲看起來並不是兒童行爲凌駕父母的理想結果。

我的解決方案是分支ControllerContext.IsChildAction並構建我自己的返回對象,但這在我看來應該由框架處理。

我相信你知道這一點,但在你的情況下,我會建議明確地設置JsonResult.ContentType爲父母的內容類型。

1

我今天有問題。原因是我需要重用現有的子操作來填充頁面上的一些json數據,以避免不必要的ajax請求。

基於Jamie和Niv的想法,我創建了以下輔助方法。

public static MvcHtmlString ChildAction(this HtmlHelper htmlHelper, ActionResult result) 
{ 
    var aux = htmlHelper.ViewContext.HttpContext.Response.ContentType; 
    var actionResult = htmlHelper.Action(result); 
    htmlHelper.ViewContext.HttpContext.Response.ContentType = aux; 
    return actionResult; 
} 

呼叫Html.ChildAction代替Html.Action當你需要使用返回JSON數據子操作的結果。

+0

謝謝,我喜歡這個解決方法,它似乎是最乾淨的。我只是將擴展名重命名爲例如「MimePreserveChildAction」,所以其他開發人員很清楚這種方法的目的是什麼。 – 2014-07-29 11:28:03