2010-03-15 4 views
13

Il semble que l'appel Html.RenderAction dans les applications Asp.Net MVC2 peut modifier le type mime de la page si le type de l'action enfant est différent de celui de l'action parent.Asp.Net MVC2 RenderAction modifie le type de page mime?

Le code ci-dessous (test dans MVC2 RTM), qui me semble sensé, retournera un résultat de type application/json en appelant Home/Index. Au lieu d'afficher la page, le navigateur affichera et vous demandera si vous voulez le télécharger.

Ma question: Ai-je raté quelque chose? Est-ce un bug? Si oui, quelle est la meilleure solution de contournement?

contrôleur

:

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

Vue:

<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> 

Répondre

8

Ce n'est pas un bug. Le type JsonResult est censé définir le résultat sur JSON, car c'est généralement ce que vous voulez.

Vous ne voulez pas vraiment un résultat JSON ici, vous voulez une chaîne JSON . Alors pourquoi ne pas écrire ça?

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

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

cela fonctionnera ... il ne semble pas qu'une action enfant devrait être capable de changer le ContentType de la page entière. –

+0

Notez que JavaScriptSerializer(). Serialize ne sérialise pas correctement les guillemets intégrés, contrairement à la méthode Json. Vous aurez besoin de quelque chose comme: Func safeForJson = (s) => { return s.NotNull(). Replace ("\" "," \\\ ""); }; –

+0

Désolé, la méthode NotNull est la mienne mais s'assure que la chaîne d'entrée n'est pas nulle (natch). –

3

Ceci peut être résolu en forçant explicitement le type mime « retour » à text/html:

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

Il ne semble pas comme cela devrait être nécessaire, cependant.

+1

Cela ne résout pas tellement le problème que le cacher. 'JsonResult' change encore' ContentType' ici; ça change juste à ce que vous (actuellement!) attendez qu'il soit. –

+0

et pour moi ça retourne juste un fichier texte avec le résultat Json dessus ... Est-ce juste moi ou est-ce que cette poubelle est incroyablement boguée ... Qui a écrit cette merde de toute façon? – SoftwareSavant

1

Tout comme le type de contenu Craig Stuntz said est supposé changer.

Une meilleure approche serait d'appeler cette action avec AJAX, puis d'affecter l'objet retourné à la variable states dans le code JavaScript.

+1

Pouvez-vous suggérer un scénario dans lequel ce comportement (action enfant modifiant le ContentType de la page) est réellement ce que vous voulez? –

+0

@ Gabe Moothart, je ne peux pas penser à un scénario où vous voudriez que cela se produise. Mais le problème est que le problème n'est pas la modification du ContentType. Le problème consiste à appeler une action Résultat ** JSON ** lors du rendu d'une vue ** HTML **. JsonResult définit la propriété ContentType de l'objet de requête sur 'application/json' comme cela est supposé le faire. Mais malheureusement, puisque vous appelez cela depuis une vue HTML, le type de la réponse d'origine change comme vous le voyez. –

8

I Considérez ceci comme un bug. Si c'est une action enfant en cours de rendu, pourquoi cela changerait la réponse d'action parent? La même chose se produit avec Html.Action, qui le rend dans une chaîne. Mon contournement est en train de faire:

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

après avoir appelé Html.Action. Je suppose que quelqu'un pourrait écrire un wrapper Html l'extension Helper, quelque chose comme:

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

Vous n'êtes pas manque quelque chose (à moins que je suis trop) et je pense que cela est un bug. J'ai le même problème dans ASP.NET MVC3.

Nous avons une action de contrôleur qui renvoie le contenu d'un système de gestion de contenu simple. Le CMS permet à l'utilisateur de définir le type de contenu retourné (par exemple text/plain ou text/xml).

L'action du contrôleur est appelée directement ou appelée en tant qu'action enfant afin de permettre à une vue de contenir des éléments gérés par le contenu. Si un contenu est créé avec un type de contenu "text/plain" et qu'il est incorporé dans une vue ASP.NET MVC, le type de contenu du parent est remplacé et le navigateur affiche le code HTML.Gabe, je pense que vous avez frappé le clou dans la tête en ce qu'il ne semble pas y avoir un scénario où l'action de l'enfant outrepassant le parent est un résultat souhaitable.

Ma solution est de se lier sur ControllerContext.IsChildAction et de construire mon propre objet de retour, mais à mon avis, c'est quelque chose qui devrait être géré par le framework.

Je suis sûr que vous êtes au courant de cela, mais dans votre cas, je suggérerais de définir explicitement JsonResult.ContentType au type de contenu du parent.

1

J'ai eu le problème aujourd'hui. La raison en est que j'ai besoin de réutiliser une action enfant existante pour remplir certaines données json sur la page afin que les requêtes ajax inutiles puissent être évitées. Sur la base de l'idée de Jamie et Niv, j'ai créé la méthode auxiliaire suivante.

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; 
} 

Appel Html.ChildAction au lieu de Html.Action lorsque vous devez utiliser résultat de l'action des enfants qui renvoie des données JSON.

+0

Merci, j'aime cette solution de contournement, il semble être le plus propre. Je voudrais juste renommer l'extension par exemple "MimePreserveChildAction", donc il est clair pour les autres développeurs quel est le but de cette méthode. –