2010-03-15 11 views
13

Parece que llamar al Html.RenderAction en aplicaciones Asp.Net MVC2 puede alterar el tipo de mime de la página si el tipo de acción del niño es diferente al de la acción principal.Asp.Net MVC2 RenderAction cambia el tipo de página de mime?

El siguiente código (prueba en MVC2 RTM), que me parece sensato, devolverá un resultado del tipo application/json al llamar al Home/Index. En lugar de desplegar la página, el navegador descartará y le preguntará si desea descargarla.

Mi pregunta: ¿Extraño algo? ¿Es esto un error? Si es así, ¿cuál es la mejor solución?

controlador:

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

vista:

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

Respuesta

8

No es un error. Se supone que el tipo JsonResult establece el resultado en JSON, porque generalmente es lo que desea.

Usted realmente no quiere un resultado JSON aquí, que desea una cadena JSON . Entonces, ¿por qué no solo escribir eso?

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

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

esto funcionará ... simplemente no parece que una acción infantil deba ser capaz de cambiar el ContentType de toda la página. –

+0

Tenga en cuenta que JavaScriptSerializer(). Serialize no serializa las citas incrustadas correctamente, a diferencia del método Json. Necesitará algo como: Func safeForJson = (s) => { return s.NotNull(). Reemplazar ("\" "," \\\ ""); }; –

+0

Lo siento, el método NotNull es el mío, pero solo me aseguro de que la cadena de entrada no sea nula (natch). –

3

esto puede ser resuelto al forzar explícitamente el tipo MIME "atrás" para text/html:

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

no parece como esto debería ser necesario, sin embargo.

+1

Eso no soluciona tanto el problema como lo esconde. 'JsonResult' todavía cambia' ContentType' aquí; simplemente lo cambia a lo que (¡actualmente!) espera que sea. –

+0

y para mí solo devuelve un archivo de texto con el resultado de Json en él ... ¿Soy yo o esta basura increíblemente defectuosa ... ¿Quién escribió esta mierda de todos modos? – SoftwareSavant

1

Me gusta Craig Stuntz said se supone que el tipo de contenido cambia.

Un mejor enfoque sería llamar a esa acción con AJAX y luego asignar el objeto devuelto a la variable states en el código JavaScript.

+1

¿Puede sugerir un escenario en el que este comportamiento (ContentType de la acción infantil que cambia la página) sea realmente lo que desea que suceda? –

+0

@Gabe Moothart, no puedo pensar en un escenario en el que te gustaría que sucediera. Pero el problema es que el problema no es el cambio del ContentType. El problema es llamar a una acción ** Json ** Result mientras se renderiza una vista ** HTML **. JsonResult establece la propiedad ObjectType de objetos de solicitud en 'application/json' como se supone que debe hacerlo. Pero desafortunadamente, como lo llamas desde una vista HTML, el tipo de respuesta original cambia como lo ves. –

8

I Considere esto un error. Si se trata de una acción secundaria que se está procesando, ¿por qué cambiaría la respuesta de acción padre? Lo mismo ocurre con Html.Action, que lo convierte en una cadena. Mi solución está haciendo:

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

después de llamar a Html.Action. Supongo que alguien podría escribir un envoltorio de extensión HTML ayudante, algo así como:

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

no te estás perdiendo algo (a menos que esté también) y yo creo que esto es un error. Tengo el mismo problema en ASP.NET MVC3.

Tenemos una acción de controlador que devuelve contenido de un sistema de administración de contenido simple. El CMS permite al usuario definir el tipo de contenido de lo que se devuelve (por ejemplo, texto/texto simple o texto/xml).

La acción del controlador se invoca directamente o se invoca como acción secundaria para permitir que una vista contenga elementos administrados por contenido.

Si se crea una porción de contenido con un tipo de contenido "text/plain", y esto está incrustado en una vista ASP.NET MVC, el tipo de contenido del elemento primario se reemplaza y el navegador muestra HTML.

Gabe, creo que has dado en el clavo porque no parece haber un escenario donde la acción del niño que predomina sobre el padre sea un resultado deseable.

Mi solución es ramificar en ControllerContext.IsChildAction y construir mi propio objeto de retorno, pero esto en mi opinión es algo que debería ser manejado por el marco.

Estoy seguro de que lo sabe, pero en su caso sugeriría explícitamente establecer JsonResult.ContentType en el tipo de contenido del elemento primario.

1

Tuve el problema hoy. La razón fue que necesito reutilizar una acción secundaria existente para completar algunos datos json en la página para evitar solicitudes ajax innecesarias.

Basado en la idea de Jamie and Niv, creé el siguiente método de ayuda.

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

llamada Html.ChildAction en lugar de Html.Action cuando se necesita usar resultado de la acción del niño que devuelve datos JSON.

+0

Gracias, me gusta esta solución, parece ser la más limpia. Simplemente cambiaría el nombre de la extensión a, por ejemplo, "MimePreserveChildAction", por lo que es claro para otros desarrolladores cuál es el propósito de este método. –

Cuestiones relacionadas