2011-08-17 18 views
7

Tengo el siguiente filtro en una acción para capturar el resultado HTML, convertirlo en una cadena, hacer algunas operaciones para modificar la cadena y devolver un resultado de contenido con el nuevo cuerda. Lamentablemente, sigo terminando con una cadena vacía.Capturar resultados HTML con un filtro de acción de controlador

private class UpdateFilter : ActionFilterAttribute 
    { 
     private Stream stream; 

     public override void OnActionExecuting(ActionExecutingContext filterContext) 
     { 
      stream = filterContext.HttpContext.Response.Filter; 
      stream = new MemoryStream(); 
      filterContext.HttpContext.Response.Filter = stream; 
     } 

     public override void OnResultExecuted(ResultExecutedContext filterContext) 
     { 
      StreamReader responsereader = new StreamReader(filterContext.HttpContext.Response.Filter); //empty stream? why? 
      responsereader.BaseStream.Position = 0; 
      string response = responsereader.ReadToEnd(); 
      ContentResult contres = new ContentResult(); 
      contres.Content = response; 
      filterContext.Result = contres; 
     } 
    } 

he inmovilizada que StreamReader (corriente) .ReadToEnd() devuelve una cadena vacía, pero no puedo entender por qué.

¿Alguna idea de cómo solucionar esto?

EDIT: He cambiado el OnActionExecuted a OnResultExecuted, y ahora se llama después de que se haya generado la vista, pero la secuencia todavía está vacía.

Respuesta

11

que resolvió este problema secuestrar el HttpWriter, y hacer que escriba en un StringBuilder en lugar de la respuesta, y luego hacer lo que sea necesario hacer a/con la respuesta antes de escribirla en la salida.

private class UpdateFilter : ActionFilterAttribute 
    { 
     private HtmlTextWriter tw; 
     private StringWriter sw; 
     private StringBuilder sb; 
     private HttpWriter output; 

     public override void OnActionExecuting(ActionExecutingContext filterContext) 
     { 
      sb = new StringBuilder(); 
      sw = new StringWriter(sb); 
      tw = new HtmlTextWriter(sw); 
      output = (HttpWriter)filterContext.RequestContext.HttpContext.Response.Output; 
      filterContext.RequestContext.HttpContext.Response.Output = tw; 
     } 

     public override void OnResultExecuted(ResultExecutedContext filterContext) 
     { 
      string response = sb.ToString(); 
      //response processing 
      output.Write(response); 
     } 
    } 
+12

advertencia: no se recomienda el uso de variables de instancia en filtros de acción. no está garantizado que obtenga una nueva instancia de ActionFilterAttribute en cada solicitud. Basé mi código en esta respuesta y me metí en problemas cuando llegó la producción con miles de solicitudes por segundo: los hilos (hilos) se estaban cruzando. almacene las variables de instancia en filterContext.HttpContext.Items como se sugiere en esta publicación: http: // stackoverflow.com/a/8937793/140449 – jaminto

2

Intente rebobinar la secuencia al principio configurando Position = 0; antes de leerlo.

public override void OnActionExecuted(ActionExecutedContext filterContext) 
{ 
    stream.Position = 0; 
    string response = new StreamReader(stream).ReadToEnd(); 
    ContentResult contres = new ContentResult(); 
    contres.Content = response; 
    filterContext.Result = contres; 
} 
+0

Eso no solucionarlo, pero sí me llevan a notar que la Posición ya es 0. Entonces parece que la transmisión debe estar vacía ... Me pregunto por qué – yoozer8

0

¿Puedes verificar que la transmisión no sea NULL en el método OnActionExectuted? No estoy seguro del estado de la corriente variable se almacena a través del proceso ..

¿Por qué no tratar de conseguir la corriente fuera de la filterContext:

public override void OnActionExecuted(ActionExecutedContext filterContext) 
{ 
    var stream = filterContext.HttpContext.Response.Filter; 
    string response = new StreamReader(stream).ReadToEnd(); 
    ContentResult contres = new ContentResult(); 
    contres.Content = response; 
    filterContext.Result = contres; 
} 
+0

Bueno, pensé que esta sería la respuesta, pero tengo el mismo problema. La secuencia que obtengo de filterContext.HttpContext.Response.Filter tiene una longitud 0. – yoozer8

1

Creo que he desarrollado una forma bastante buena de hacerlo.

  • reemplazar el filtro Reponse con uno personalizado
  • Este filtro toma un delegado a un método abstracto que toma una corriente
  • Esta el delegado, y por lo tanto el método abstracto se llaman en el cierre de la corriente de , es decir, cuando todo el HTML está disponible
  • Reemplace el método OnClose y juegue con la transmisión como desee.

public abstract class ReadOnlyActionFilterAttribute : ActionFilterAttribute 
{ 
    private delegate void ReadOnlyOnClose(Stream stream); 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     filterContext.HttpContext.Response.Filter = new OnCloseFilter(
      filterContext.HttpContext.Response.Filter, 
      this.OnClose); 
     base.OnActionExecuting(filterContext); 
    } 

    protected abstract void OnClose(Stream stream); 

    private class OnCloseFilter : MemoryStream 
    { 
     private readonly Stream stream; 

     private readonly ReadOnlyOnClose onClose; 

     public OnCloseFilter(Stream stream, ReadOnlyOnClose onClose) 
     { 
      this.stream = stream; 
      this.onClose = onClose; 
     } 

     public override void Close() 
     { 
      this.Position = 0; 
      this.onClose(this); 
      this.Position = 0; 
      this.CopyTo(this.stream); 
      base.Close(); 
     } 
    } 
} 

continuación, se pueden derivar de este a otro atributo para acceder a la transmisión y obtener el código HTML:

public class MyAttribute : ReadOnlyActionFilterAttribute 
{ 
    protected override void OnClose(Stream stream) 
    { 
     var html = new HtmlDocument(); 
     html.Load(stream); 
     // play with html 
    } 
} 
+0

La pregunta es sobre la actualización del resultado, esto no es posible con su solución, ¿o sí? – Gaz

+0

@Gaz Debe ser lo suficientemente simple como para modificarlo para que funcione. Hace bastante tiempo, así que no puedo recordar lo siento! –

+0

@Gaz, esto debería llevar al OP en la dirección correcta. El problema es que la secuencia predeterminada en 'filterContext.RequestContext.HttpContext.Response' no admite la lectura, por lo que debe reemplazar la secuencia con una que permita la lectura. – ps2goat

Cuestiones relacionadas