Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a notification when ASP.NET Web API completes sending to the client

I'm using Web API to stream large files to clients, but I'd like to log if the download was successful or not. That is, if the server sent the entire content of the file.

Is there some way to get a a callback or event when the HttpResponseMessage completes sending data?

Perhaps something like this:

var stream = GetMyStream();
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");    
// This doesn't exist, but it illustrates what I'm trying to do.
response.OnComplete(context =>
{
    if (context.Success)
        Log.Info("File downloaded successfully.");
    else
        Log.Warn("File download was terminated by client.");
});
like image 758
ligos Avatar asked Dec 20 '12 00:12

ligos


1 Answers

EDIT: I've now tested this using a real connection (via fiddler).

I inherited StreamContent and added my own OnComplete action which checks for an exception:

public class StreamContentWithCompletion : StreamContent
{
    public StreamContentWithCompletion(Stream stream) : base (stream) { }
    public StreamContentWithCompletion(Stream stream, Action<Exception> onComplete) : base(stream) 
    { 
        this.OnComplete = onComplete; 
    }

    public Action<Exception> OnComplete { get; set; }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        var t = base.SerializeToStreamAsync(stream, context);
        t.ContinueWith(x =>
        {
            if (this.OnComplete != null)
            {
                // The task will be in a faulted state if something went wrong. 
                // I observed the following exception when I aborted the fiddler session: 
                // 'System.Web.HttpException (0x800704CD): The remote host closed the connection.'
                if (x.IsFaulted)
                    this.OnComplete(x.Exception.GetBaseException());
                else
                    this.OnComplete(null);
            }
        }, TaskContinuationOptions.ExecuteSynchronously);
        return t;
    }
}

Then I use it like so:

var stream = GetMyStream();
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContentWithCompletion(stream, ex =>
{
    if (ex == null)
        Log.Info("File downloaded successfully.");
    else
        Log.Warn("File download was terminated by client.");
});
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");    
return response;
like image 164
ligos Avatar answered Oct 07 '22 21:10

ligos