Checking Client Download Success with ASP.NET MVC

Scenario: You want to know if a client completes a large download successfully.

Possible Solution: Create a custom ActionResult (perhaps derived from FileStreamResult) that streams the data and checks to see if the client remains connected.

public class CheckedFileStreamResult : FileStreamResult
{
    public CheckedFileStreamResult(FileStream stream, string contentType)
        :base(stream, contentType)
    {
        DownloadCompleted = false;
    }

    public bool DownloadCompleted { get; set; }

    protected override void WriteFile(HttpResponseBase response)
    {
        var outputStream = response.OutputStream;
        using (FileStream)
        {
            var buffer = new byte[_bufferSize];
            var count = FileStream.Read(buffer, 0, _bufferSize);
            while(count != 0 && response.IsClientConnected)
            {                 
                outputStream.Write(buffer, 0, count);
                count = FileStream.Read(buffer, 0, _bufferSize);
            }
            DownloadCompleted = response.IsClientConnected;
        }
    }
    
    private const int _bufferSize = 0x1000;
}

You can now log or audit the DownloadCompleted property of the result from an action filter. I'm sure this isn't 100% foolproof, but it seems to work reasonably well. Note: The IsClientConnected property of the response only tells the truth when running under IIS. With the WebDev server the property always returns true.

Print | posted @ Wednesday, June 23, 2010 9:12 PM

Comments on this entry:

Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Nick Berardi at 6/24/2010 6:57 AM

Hi Scott,

Don't forget to turn off the buffer. So that your file is sent in chuncks to the client

response.BufferOutput = false;

I don't know if you set this in your web.config or somewhere else, but it is important for your readers to understand the ASP.NET by default buffers all output before it is sent back to the client.
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by scott at 6/24/2010 8:11 AM

Good point, Nick. Thanks.
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Erik at 6/24/2010 10:02 AM

I wonder if passing an Action<bool> to trigger on complete would work..

Nice sample anyhow :D

Erik
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Imran Balcoh at 7/4/2010 2:03 PM

First point is that you need to inherit your class from FileResult instead of FileStreamResult. Because WriteFile is already overriden in FileStreamResult class.

Second point is that due to Lazy execuation of ActionResult in ASP.NET MVC, there is no way to query DownloadCompleted property. The reason is that ASP.NET MVC internally calls the ExecuteResult method which results in call of WriteFile method.
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Scott at 7/4/2010 4:16 PM

@Imran - Sorry - I don't understand either of your points.

When we derive from FileSteamResult we can still override WriteFile - this is a streaming operation after all.

It's easy to check DownloadCompleted during OnActionExecuted (which is after the result executes).
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Imran Balcoh at 7/4/2010 10:37 PM

@Scott, I am not saying that it is incorrect. I am just saying that it is illogical that a member which is override in parent class again override in child class.

For my second point, the only way to inspect DownloadCompleted property is to use ResultExecuted filter not ActionExecuted filter because ActionExecuted is executed before WriteFile method. But at this point you have no choice to change Result.
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by scott at 7/5/2010 10:28 AM

@Imran - Ah, yes. We could debate this one ;)

On your second point - yes, my mistake. I meant to say OnResultExecuted not OnActionExecuted.

protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
var download = filterContext.Result as CheckedFileStreamResult;
if(download != null)
{
// ...
}

}

I'm not worried about changing the result - just logging if the download appears to have been successful.
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Zen at 7/5/2010 10:42 AM

@Imran

just curious, why is it not logical to override a method in a child class when the same method is overriden in the parent class. Can you point me to any resource that touch upon this topic?

Thanks!

Zen
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Thanigainathan at 7/5/2010 1:19 PM

Hi,
You need to be more precise. You have to mention this is article related to MVC in very first stage. Please take this as my request.Also please mention where this will be used in applciation. An example will be enough.

Thanks,
Thani
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by scott at 7/5/2010 2:05 PM

@Thani - the title says "with ASP.NET MVC".
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Imran Balcoh at 7/5/2010 2:20 PM

@Zen,
I have seen lot of methods which are overridden in child and are declared as virtual in parent but never seen a method which is defined as override in parent and again overridden in child.

But the truth fact is that override method is by default virtual for it's child classes(From a Microsoft Book). So I am agreeing that your method is not illogical.
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Imran Balcoh at 7/5/2010 2:21 PM

@Zen,
I have seen lot of methods which are overridden in child and are declared as virtual in parent but never seen a method which is defined as override in parent and again overridden in child.

But the truth fact is that override method is by default virtual for it's child classes(From a Microsoft Book). So I am agreeing that your method is not illogical.
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Frank at 7/6/2010 2:10 AM

Hi Scott

Could you make a complete example?

/Frank
  
Gravatar # re: Checking Client Download Success with ASP.NET MVC
by Doug Rathbone at 7/12/2010 8:27 PM

This is a cool idea - i'd never thought of checking for client connection at the end of the stream.

Apologies if you think this is blatant spam, but you could then use my open source Google Analytics wrapper - GaDotNet to log the download success to your GA account :)
www.diaryofaninja.com/projects/details/ga-dot-net

keep up the great work - you have a new subscriber!
  
Comments have been closed on this topic.
Scott Allen
Posts - 869
Comments - 4493
Stories - 14