【问题标题】:asp.net MVC 3/4 equivalent to a response.filterasp.net MVC 3/4 相当于一个 response.filter
【发布时间】:2012-05-14 22:00:58
【问题描述】:

我需要拦截所有将发送到浏览器的 html 并替换其中的一些标签。这需要在全球范围内针对每个视图进行。使用 C# 在 ASP.NET MVC 3 或 4 中执行此操作的最佳方法是什么?过去,我在 ASP.net Webforms 中使用 Global.asax (vb) 中的“response.filter”完成此操作

Private Sub Global_PreRequestHandlerExecute(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRequestHandlerExecute
    Response.Filter = New ReplaceTags(Response.Filter)
End Sub

这调用了我创建的一个类,它继承自 system.io.stream 并遍历 html 以替换所有标签。 我不知道如何使用 C# 在 ASP.NET MVC 4 中执行此操作。正如您可能已经注意到的那样,我是 MVC 世界的新手。

【问题讨论】:

标签: asp.net asp.net-mvc-3 response.filter


【解决方案1】:

您仍然可以在 ASP.NET MVC 中使用响应过滤器:

public class ReplaceTagsFilter : MemoryStream
{
    private readonly Stream _response;
    public ReplaceTagsFilter(Stream response)
    {
        _response = response;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        var html = Encoding.UTF8.GetString(buffer);
        html = ReplaceTags(html);
        buffer = Encoding.UTF8.GetBytes(html);
        _response.Write(buffer, offset, buffer.Length);
    }

    private string ReplaceTags(string html)
    {
        // TODO: go ahead and implement the filtering logic
        throw new NotImplementedException();
    }
}

然后编写一个自定义动作过滤器来注册响应过滤器:

public class ReplaceTagsAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var response = filterContext.HttpContext.Response;
        response.Filter = new ReplaceTagsFilter(response.Filter);
    }
}

现在剩下的就是装饰您想要应用此过滤器的控制器/操作:

[ReplaceTags]
public ActionResult Index()
{
    return View();
}

如果您想应用于所有操作,或者将其注册为 Global.asax 中的全局操作过滤器。

【讨论】:

  • 过滤器仅在代码退出 OnActionExecuting 函数时才会执行。在实际写出响应之前如何访问流缓冲区?
  • 响应过滤器的全部意义在于修改响应流。但为了能够对其进行修改,必须先写入此流。
  • 这似乎不适用于 Razor。我在尝试向响应添加过滤器时收到“不允许过滤”HttpException。
  • @MaximV.Pavlov 根据 ASP.NET 团队的一位成员的说法:Response filters are not supported with Razor because of the way Razor buffers output
【解决方案2】:

答案是正确的,但是。在使用了一段时间后,我遇到了一个响应被拆分为多个部分以致 html 不正确的情况

Part 1: 
<html>.....<labe

Part 2: 
l/>...</html>

部分渲染也可能出现意外情况。他们的 html 也不在主流之外。 所以我的解决方案是在所有流式传输完成后在 Flush 方法中进行。

    /// <summary>
    /// Insert messages and script to display on client when a partial view is returned
    /// </summary>
    private class ResponseFilter : MemoryStream
    {
        private readonly Stream _response;
        private readonly IList<object> _detachMessages;

        public override void Flush()
        {

            // add messages and remove
            // filter is called for a number of methods on one page (BeginForm, RenderPartial...)
            // so that we don't need to add it more than once

            var html = MessageAndScript(_detachMessages);
            var buffer = Encoding.UTF8.GetBytes(html);
            _detachMessages.Clear();
            _response.Write(buffer, 0, buffer.Length);

            base.Flush();
        }

        public ResponseFilter(Stream response, IList<object> detachMessages)
        {
            _response = response;
            _detachMessages = detachMessages;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            _response.Write(buffer, offset, buffer.Length);    
        }

        private static string MessageAndScript(IList<object> detachMessages)
        {

            if (detachMessages.Count == 0)
                return null;

            var javascript = CustomJavaScriptSerializer.Instance.Serialize(detachMessages);

            return "$(function(){var messages = " + javascript + @";
// display messages
base.ajaxHelper.displayMessages(messages);
})";
        }
    }

【讨论】:

  • 我经历过,当流分裂时,我最终会得到很多奇怪的“??”源代码中的符号,从而使页面看起来很奇怪。你遇到过吗?
猜你喜欢
  • 1970-01-01
  • 2011-10-08
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-04
相关资源
最近更新 更多