为mvc添加全局过滤器实现Response重写


我们公司的网站都是使用的是mvc框架,最近有这样的需求.因为之前的一些东西在开始开发的时候写死了.比如静态资源地址或者别的站点的地址.但是最近改版的时候需要重新配置地址.如果全局搜索修改地址的话工作量太大.于是想着是否可以使用全局过滤器来重写Response流来实现.下面给出解决方案. 具体就是重写ActionFilterAttribute.然后为Response.Filter重置为我们实现了我们业务需要的Filter. 首先创建过滤器.如下:

public class RewriteHttpsFilterAttribute : ActionFilterAttribute
   {
       public override void OnActionExecuting(ActionExecutingContext filterContext)
       {
           var response = filterContext.HttpContext.Response;
           string IsRedirectToHttps = ConfigurationManager.AppSettings["IsRedirectToHttps"];
           string IsRewriteToHttps = ConfigurationManager.AppSettings["IsRewriteToHttps"];
#if Release
           if (!string.IsNullOrEmpty(IsRedirectToHttps) && IsRedirectToHttps == "1")
           {
               var request = filterContext.HttpContext.Request;
               if (request.Url.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase))
               {
                   string redirurl = request.Url.ToString().Replace("http://", "https://");
                   filterContext.Result = new RedirectResult(redirurl);
                   return;
               }
           }
#endif
           if (!string.IsNullOrEmpty(IsRewriteToHttps) && IsRewriteToHttps == "1")
           {
               if (response.Filter == null) return;
               if (response.ContentType == "text/html" && response.StatusCode == 200)
               {
                   Func<string, string> todo = content =>
                   {
                       StringBuilder sb = new StringBuilder(content);
                       //todo regex
                       Regex re = new Regex(@"regex", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                       Dictionary<string, string> replacements = new Dictionary<string, string>();
                       foreach (Match match in re.Matches(content))
                       {
                           if (match.Success)
                           {
                               //todo
                           }
                       }
                       foreach (var replacement in replacements)
                       {
                           sb = sb.Replace(replacement.Key, replacement.Value);
                       }
                       return sb.ToString();
                   };
                   response.Filter = new RewriteResponse(response.Filter, response.ContentEncoding, todo);
               }
           }
       }
   }

接下来就是实现一个类.继承Stream就可以了.

public class RewriteResponse : Stream
   {
       private Stream filter;
       private Encoding encoding;
       private readonly MemoryStream cacheStream = new MemoryStream();
       private Func<string, string> todo;

       public RewriteResponse(Stream filter, Encoding encoding, Func<string, string> todo)
       {
           this.filter = filter;
           this.encoding = encoding;
           this.todo = todo;
       }

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

       public override void Flush()
       {
           if (cacheStream.Length > 0 && todo != null)
           {
               string content = encoding.GetString(cacheStream.ToArray(), 0, (int)cacheStream.Length);

               string data = todo(content);
               var buffer = encoding.GetBytes(data);
               this.filter.Write(buffer, 0, buffer.Length);
               cacheStream.SetLength(0);
           }
           this.filter.Flush();
       }

       public override long Seek(long offset, SeekOrigin origin)
       {
           return this.filter.Seek(offset, origin);
       }

       public override void SetLength(long value)
       {
           this.filter.SetLength(value);
       }

       public override int Read(byte[] buffer, int offset, int count)
       {
           return this.filter.Read(buffer, offset, count);
       }

       public override bool CanRead
       {
           get { return this.filter.CanRead; }
       }

       public override bool CanSeek
       {
           get { return this.filter.CanSeek; }
       }

       public override bool CanWrite
       {
           get { return this.filter.CanWrite; }
       }

       public override long Length
       {
           get { return this.filter.Length; }
       }

       public override long Position
       {
           get { return this.filter.Position; }
           set { this.filter.Position = value; }
       }
   }

至此.大部分已经完成了.最后一步就是在Global.asax中添加我们的过滤器.如下:

      public void RegisterGlobalFilters(GlobalFilterCollection filters)
       {
           //其他过滤器
           filters.Add(new RewriteHttpsFilterAttribute());
       }

就这样.简单吧.