开发者

Using Response.Filter with Response.TransmitFile

I'm using Response.Filter in order to implement stream compression in accordance with HTTP Request Header Acce开发者_运维百科pt-Encoding

Here's the important stuff:

        if (AcceptEncoding.Contains("deflate") || AcceptEncoding == "*")
        {
             HttpApp.Response.Filter = new DeflateStream(PreviousOutputStream, CompressionMode.Compress);
             HttpApp.Response.AppendHeader("Content-Encoding", "deflate");
        }

By and large this works as intended. However, I'm in a situation where I'm using an ActionResult on an MVC Controller to serve up files to the user agent:

        Response.Clear();
        Response.Headers["Content-Type"] = contentType;
        Response.Headers["Content-Length"] = contentLength;

        if (Request.QueryString["dl"] == "1")
        {
            Response.Headers["Content-Disposition"] = "attachment; filename=" + fileInfo.Name;
        }

        Response.Flush();
        Response.TransmitFile(fileInfo.FullName);

To be more exact, the action method returns new EmptyResult() after the Response.TransmitFile() call. This works exactly as intended without the Response.Filter modification.

In this situation, the response entity reaches the user agent garbled and unintelligible. FireFox's Poster addon shows empty entities or jumbled entities coming back.


If you can help it, definitely look for alternatives, because manually doing compression in ASP.NET is NOT fun. But, if you are as hard-headed as I am, I submit to you the following.

First of all: do NOT use .NET's built-in compression stream classes. They are buggy and can truncate bytes off the end of streams at random. I've been using DotNetZip with good results: http://dotnetzip.codeplex.com/

Now, some additional notes:

  • Response.TransmitFile() doesn't work with response filtering.
  • Response.BinaryWrite() doesn't work with response filtering, so you can't loop over the contents of the file and write it out that way.
  • Response.OutputStream doesn't work with response filtering, so you can't loop over the contents of the file and write it out THAT way, either.
  • Response.WriteFile() DOES work with response filtering, but it loads the entire file into memory and keeps it there until the client closes the connection, which doesn't work well for large files.
  • And to make things just that little bit more fun: response filtering stops working if you set Response.BufferOutput to false. (I just spent literally hours figuring that out)

Obviously, there's a LOT of different issues surrounding response filtering and writing to the output stream. Using Reflector and lots of experimentation, this is the best ("best" being in terms of working correctly in a variety of scenarios) solution I've found thus far:

  1. Write a class that extends Encoding and call it BinaryEncoding. Implement all the methods so that they copy characters and bytes correctly, but of course doing the necessary type casts.

  2. Set Response.ContentEncoding to an instance of BinaryEncoding (you can use the singleton pattern quite successfully for this).

  3. Open your file with FileStream.

  4. Create a new StreamReader(fileStream, new BinaryEncoding(), false). That "false" parameter is very important, it stops the StreamReader from eating byte order marks and overriding your BinaryEncoding.

  5. Allocate a buffer of char[] (I've found that 32KB is a good size).

Then, in a loop:

int n = StreamReader.Read(buffer, 0, buffer.Length);
Response.Write(buffer, 0, n);
Response.Flush();

Until n is 0.

Be warned: this method results in fairly high CPU usage. On a 100 megabit LAN, CPU usage on one core goes to around 40-50% for a single client downloading at 10MB/sec. I wish I could find a better way... If I had Reflector Pro, I might be able to find one.


If you are using IIS7 or IIS7.5 I would suggest using the HTTP Compression module rather than rolling your own. It might help solve the problem.

http://technet.microsoft.com/en-us/library/cc771003(WS.10).aspx

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜