Capturing HTML output with a controller action filter

前端 未结 4 1968
温柔的废话
温柔的废话 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条回答
  •  -上瘾入骨i
    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
        }
    }
    

提交回复
热议问题