Capturing HTML output with a controller action filter

前端 未结 4 1969
温柔的废话
温柔的废话 2020-12-14 13:17

I\'ve got the following filter in place on an action to capture the HTML output, convert it to a string, do some operations to modify the string, and return a ContentResult

相关标签:
4条回答
  • 2020-12-14 13:26

    I think I've developed a pretty good way to do this.

    • Replace the Reponse Filter with a custom one
    • This filter takes a delegate to an abstract method which takes a stream
    • This the delegate, and hence the abstract method are called on the close of the stream, i.e. when all the HTML is available
    • Override the OnClose method and play with the stream as you like.

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

    You can then derive from this to another attribute to access the stream and get the HTML:

    public class MyAttribute : ReadOnlyActionFilterAttribute
    {
        protected override void OnClose(Stream stream)
        {
            var html = new HtmlDocument();
            html.Load(stream);
            // play with html
        }
    }
    
    0 讨论(0)
  • 2020-12-14 13:30

    Can you verify that stream is not NULL in the OnActionExectuted-method? I'm not sure the state of the stream-variable is being stored through the process..

    Why don't you try to get the stream out of the 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 讨论(0)
  • 2020-12-14 13:42

    Try rewinding the stream to the beginning by setting Position = 0; before you read it.

    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 讨论(0)
  • 2020-12-14 13:48

    I solved this by hijacking the HttpWriter, and having it write into a StringBuilder rather than the response, and then doing whatever needs to be done to/with the response before writing it to the output.

     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);
            }
        }
    
    0 讨论(0)
提交回复
热议问题