Quiero generar dos vistas diferentes (una como una cadena que se enviará como un correo electrónico) y la otra la página mostrada a un usuario.
¿Es esto posible en ASP.NET MVC beta?
He probado múltiples ejemplos:
1. RenderPartial a String en ASP.NET MVC Beta
Si uso este ejemplo, recibo el mensaje "No se puede redirigir después de que se hayan enviado los encabezados HTTP".
2. MVC Framework: capturando el resultado de una vista
Si uso esto, parece que no puedo hacer un redirectToAction, ya que intenta mostrar una vista que puede no existir. Si devuelvo la vista, está completamente desordenada y no se ve del todo bien.
¿Alguien tiene alguna idea / solución para estos problemas que tengo, o tiene alguna sugerencia para solucionarlos?
¡Muchas gracias!
A continuación se muestra un ejemplo. Lo que intento hacer es crear el método GetViewForEmail :
public ActionResult OrderResult(string ref)
{
//Get the order
Order order = OrderService.GetOrder(ref);
//The email helper would do the meat and veg by getting the view as a string
//Pass the control name (OrderResultEmail) and the model (order)
string emailView = GetViewForEmail("OrderResultEmail", order);
//Email the order out
EmailHelper(order, emailView);
return View("OrderResult", order);
}
Respuesta aceptada de Tim Scott (modificada 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();
//Right, create our view
viewPage.ViewContext = new ViewContext(controllerContext, new WebFormView(viewPath, masterPath), viewData, tempData);
//Get the response context, flush it and get the response filter.
var response = viewPage.ViewContext.HttpContext.Response;
response.Flush();
var oldFilter = response.Filter;
try
{
//Put a new filter into the response
filter = new MemoryStream();
response.Filter = filter;
//Now render the view into the memorystream and flush the response
viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
response.Flush();
//Now read the rendered view.
filter.Position = 0;
var reader = new StreamReader(filter, response.ContentEncoding);
return reader.ReadToEnd();
}
finally
{
//Clean up.
if (filter != null)
{
filter.Dispose();
}
//Now replace the response filter
response.Filter = oldFilter;
}
}
Ejemplo de uso
Asumiendo una llamada desde el controlador para obtener el correo electrónico de confirmación del pedido, pasando la ubicación Site.Master.
string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);
fuente
Respuestas:
Esto es lo que se me ocurrió, y está funcionando para mí. Agregué los siguientes métodos a mi clase base de controlador. (Siempre puedo hacer estos métodos estáticos en otro lugar que acepten un controlador como parámetro, supongo)
Estilo MVC2 .ascx
Razor .cshtml style
Editar: código agregado de Razor.
fuente
Esta respuesta no está en camino. Esto es originalmente de https://stackoverflow.com/a/2759898/2318354 pero aquí he mostrado la forma de usarlo con la palabra clave "estática" para que sea común para todos los controladores.
Para eso tienes que hacer la
static
clase en el archivo de clase. (Suponga que su nombre de archivo de clase es Utils.cs)Este ejemplo es para Razor.
Utils.cs
Ahora puede llamar a esta clase desde su controlador agregando NameSpace en su archivo de controlador de la siguiente manera pasando "esto" como parámetro al controlador.
Como sugerencia dada por @Sergey, este método de extensión también puede llamar desde cotroller como se indica a continuación
Espero que esto sea útil para que el código sea limpio y ordenado.
fuente
Esto funciona para mi:
fuente
Encontré una nueva solución que representa una vista de cadena sin tener que meterse con el flujo de Respuesta del HttpContext actual (que no le permite cambiar el ContentType de la respuesta u otros encabezados).
Básicamente, todo lo que debe hacer es crear un HttpContext falso para que la vista se represente:
Esto funciona en ASP.NET MVC 1.0, junto con ContentResult, JsonResult, etc. (cambiar los encabezados en el HttpResponse original no arroja la excepción "El servidor no puede establecer el tipo de contenido después de que se hayan enviado los encabezados HTTP ").
Actualización: en ASP.NET MVC 2.0 RC, el código cambia un poco porque tenemos que pasar el
StringWriter
usado para escribir la vista enViewContext
:fuente
StringWriter
que está utilizando para escribir en elStringBuilder
, no una nueva instancia o la salida de la vista se perderá.Este artículo describe cómo representar una vista en una cadena en diferentes escenarios:
La solución / código se proporciona como una clase llamada ViewRenderer . Es parte de WestwindToolkit de Rick Stahl en GitHub .
Uso (3. - Ejemplo de WebAPI):
fuente
Si desea renunciar a MVC por completo, evitando así todo el desorden de HttpContext ...
Esto utiliza el increíble Razor Engine de código abierto aquí: https://github.com/Antaris/RazorEngine
fuente
CompilerErrors
la excepción.obtienes la vista en cadena de esta manera
Llamamos a este método de dos maneras.
O
fuente
Consejo adicional para ASP NET CORE:
Interfaz:
Implementación:
Registro en
Startup.cs
Y uso en el controlador:
fuente
Estoy usando MVC 1.0 RTM y ninguna de las soluciones anteriores funcionó para mí. Pero este sí:
fuente
Vi una implementación para MVC 3 y Razor desde otro sitio web, funcionó para mí:
Más sobre Razor render- MVC3 View Render to String
fuente
Para representar una vista de una cadena en la capa de servicio sin tener que pasar ControllerContext, hay un buen artículo de Rick Strahl aquí http://www.codemag.com/Article/1312081 que crea un controlador genérico. Resumen del código a continuación:
Luego, para representar la Vista en la clase de Servicio:
fuente
Consejo rapido
Para un modelo fuertemente tipado simplemente agréguelo a la propiedad ViewData.Model antes de pasar a RenderViewToString. p.ej
fuente
Para repetir una pregunta más desconocida, eche un vistazo a MvcIntegrationTestFramework .
Le ahorra escribir sus propios ayudantes para transmitir el resultado y está demostrado que funciona lo suficientemente bien. Supongo que esto estaría en un proyecto de prueba y, como beneficio adicional, tendría las otras capacidades de prueba una vez que tenga esta configuración. La molestia principal probablemente sería resolver la cadena de dependencia.
fuente
Aquí hay una clase que escribí para hacer esto para ASP.NETCore RC2. Lo uso para generar correo electrónico html con Razor.
fuente
Encontré una mejor manera de representar la página de vista de afeitar cuando recibí un error con los métodos anteriores, esta solución para el entorno de formularios web y el entorno de mvc. No se necesita controlador.
Aquí está el ejemplo de código, en este ejemplo simulé una acción mvc con un controlador http asíncrono:
fuente