Quiero generar dos vistas diferentes (una como cadena de texto que se enviará por correo electrónico), y la otra la página mostrada a un usuario.
¿Es posible en ASP.NET MVC beta?
He intentado varios ejemplos:
1. RenderPartial to String in ASP.NET MVC Beta
Si utilizo este ejemplo, recibo el mensaje "Cannot redirect after HTTP headers have been sent.".
2. MVC Framework: Capturing the output of a view
Si lo utilizo, parezco no poder realizar un redirectToAction, ya que intenta renderizar una vista que puede que no exista. Si retorno la vista, está completamente desordenada y no se ve bien en absoluto.
¿Alguien tiene alguna idea/solución para estos problemas que tengo, o tiene alguna sugerencia mejor?
¡Muchas gracias!
A continuación se muestra un ejemplo. Lo que estoy intentando hacer es crear el método GetViewForEmail:
public ActionResult OrderResult(string ref)
{
//Obtener la orden
Order order = OrderService.GetOrder(ref);
//El ayudante del correo haría la mayor parte del trabajo al obtener la vista como texto
//Pasar el nombre del control (OrderResultEmail) y el modelo (order)
string emailView = GetViewForEmail("OrderResultEmail", order);
//Enviar por correo electrónico la orden
EmailHelper(order, emailView);
return View("OrderResult", order);
}
Respuesta aceptada de Tim Scott (cambiada y formateada un poco por mí):
public virtual string RenderViewToString(
ControllerContext controllerContext,
string viewPath,
string masterPath,
ViewDataDictionary viewData,
TempDataDictionary tempData)
{
Stream filter = null;
ViewPage viewPage = new ViewPage();
//Crear nuestra vista
viewPage.ViewContext = new ViewContext(controllerContext, new WebFormView(viewPath, masterPath), viewData, tempData);
//Obtener el contexto de respuesta, vaciarlo y obtener el filtro de respuesta.
var response = viewPage.ViewContext.HttpContext.Response;
response.Flush();
var oldFilter = response.Filter;
try
{
//Poner un nuevo filtro en la respuesta
filter = new MemoryStream();
response.Filter = filter;
//Ahora renderizar la vista en el memorystream y vaciar la respuesta
viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
response.Flush();
//Ahora leer la vista renderizada.
filter.Position = 0;
var reader = new StreamReader(filter, response.ContentEncoding);
return reader.ReadToEnd();
}
finally
{
//Limpiar.
if (filter != null)
{
filter.Dispose();
}
//Ahora reemplazar el filtro de respuesta
response.Filter = oldFilter;
}
}
Ejemplo de uso
Suponiendo una llamada desde el controlador para obtener el correo de confirmación del pedido, pasando la ubicación de Site.Master.
string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);
2 votos
¿Cómo se puede usar esto con una vista que sea fuertemente tipada? Es decir, ¿cómo puedo pasar un modelo a la página?
0 votos
No se puede usar esto y crear JsonResult después, porque el tipo de contenido no se puede establecer después de que se hayan enviado las cabeceras (porque Flush las envía).
0 votos
Porque no hay una única respuesta correcta, supongo. :) Creé una pregunta que era específica para mí, pero sabía que también sería una pregunta común.
2 votos
La solución sugerida no funciona en MVC 3.
1 votos
@Qua: La solución sugerida tiene más de dos años. ¡No esperaría que funcionara para MVC 3 tampoco! Además, ahora hay mejores formas de hacer esto.
0 votos
@BishopBarber ¡Gracias. ¡Arreglado!