Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Completed event for FilePathResult

I want to do something after user finishes downloading

public class TestController : Controller
{
    public FilePathResult Index()
    {
        return File("path/to/file", "mime");
    }
}

What I tried is to add the following events to test controller but they all fires before user finish downloading (except destructor it never gets called)

protected override void EndExecute(IAsyncResult asyncResult)
{
    base.EndExecute(asyncResult);
}
protected override void EndExecuteCore(IAsyncResult asyncResult)
{
    base.EndExecuteCore(asyncResult);
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    base.OnActionExecuted(filterContext);
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
    base.OnResultExecuted(filterContext);
}
protected override void Dispose(bool disposing)
{
    base.Dispose(disposing);
}
~TestController()
{
    //
}
like image 972
Almis Avatar asked Sep 02 '15 09:09

Almis


2 Answers

You can try to use custom FileStreamResult as described here - http://odetocode.com/blogs/scott/archive/2010/06/23/checking-client-download-success-with-asp-net-mvc.aspx.

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;
}

As you see, WriteFile method is overriden and custom logic is implemented to serve response.OutputStream to client by reading chunks from FileStream and writing to OutputStream. At the end of this process you may consider file downloaded. Then you can check DownloadCompleted in OnResultExecuted handler of controller. Alternatively, you can try pass custom Action delegate to CheckedFileStreamResult constructor and invoke that when download completes (instead of using DownloadCompleted flag).

like image 59
Evk Avatar answered Oct 04 '22 06:10

Evk


There is ready-made solution for jQuery, check this out http://johnculviner.com/jquery-file-download-plugin-for-ajax-like-feature-rich-file-downloads/
The idea is pretty simple: on server-side you create attribute which sets custom cookie after action executed, on client-side you use setTimeout to check this cookie and do something when it'll come.

like image 44
HollyDolly Avatar answered Oct 04 '22 08:10

HollyDolly