Completed event for FilePathResult
Asked Answered
C

5

15

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()
{
    //
}
Crinose answered 2/9, 2015 at 9:54 Comment(0)
B
3

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).

Backman answered 8/9, 2015 at 20:34 Comment(0)
A
3

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.

Almazan answered 7/9, 2015 at 9:13 Comment(2)
I wouldn't recommend using cookies for anything anymore. (unless dipped in your favorite beverage).Taggart
I'm very grateful for argumentative comment. Of course, you can use different ways to check some info from server, but this is the fastest/simplest in this caseAlmazan
B
3

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).

Backman answered 8/9, 2015 at 20:34 Comment(0)
P
0

The client (a browser) is doing the downloading, you the server are not informed when it is done. With HTTP you cannot tell the client to do something else after downloading.

Paracasein answered 2/9, 2015 at 10:7 Comment(1)
I don't want to tell him to do something else. The server sending the stream so it should know when it finished.Crinose
G
0

If you want to do something on server, may be you can use PushStreamContent. Here is stackoverflow answer and a blog entry.

Geller answered 8/9, 2015 at 7:37 Comment(3)
Is PushStreamContent based on SignalR? Can you provide me some source to read? I guess it relies on Headers.TransferEncodingChunked = true..Geller
You are right. I was wrong, it is not dependent on signalR. I deleted my comment.Paquette
Thanks. But as you have deleted your comment, mine looks orphan.Geller
P
0

Generally you need two threads, one for downloading and one for notification. On the server side these threads share the info about how many bytes from file length was sent. The downloading thread is made via IHttpHandler, where you parse the http query and write bytes to http response buffer by buffer and updates the shared information with notification thread. The notification thread is some repeating ajax query from the page where did you started downloading. You can also render the downloading progressbar with jquery.

Paquette answered 8/9, 2015 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.