Skip to content

[API Proposal]: Event when a HttpResponseMessage is complete #86502

@JamesNK

Description

@JamesNK

Background and motivation

HttpClient and its middleware friends are based around passing the request message down through a nested HttpMessageHandler.SendAsync pipeline and returning the response message back.

The response being returned from SendAsync has historically been used to indicate that a request is complete. However, it only indicates the response header headers have been returned (apart from HttpClient and its option to read the response to completion before returning). This means that code that cares about the request being finished, such as counters, activities, and diagnostic source events, are reporting a HTTP request is finished even though the response body is still being read.

This becomes obvious in longer-running HTTP requests, such as gRPC streaming, where the response headers are returned almost immediately. Still, the response body periodically returns messages written by the server.

There should be an event that libraries and apps can subscribe to that indicates when the request is complete.

Potential users:

API Proposal

An event on HttpResponseMessage that reports when the overall request is considered complete.

namespace System.Net.Http;

public class HttpResponseMessage
{
    // Option 1: Cancellation token
    public CancellationToken Completed { get; }

    // Option 2: Register callback
    public void OnCompleted(Action<HttpResponseMessage> callback);
}

API options:

  • CancellationToken might not be the right thing. I can't think of a scenario where someone would use it with an async method call that takes a token. I suggest it because it is similar to ASP.NET Core's HttpContext.RequestAborted token.
  • HttpResponseMessage.OnCompleted(Action callback) may be preferable. It's like ASP.NET Core's HttpResponse.OnCompleted.

When these APIs are used, the registered callback is invoked if the response is complete.

The interesting discussion point here is: when is the overall request considered complete?

I think a request should be considered complete when both of these events are true (or the HttpResponseMessage is explicitly disposed):

  1. The HttpResponseMessage.Content has been read to the end (or no content was returned at all),
  2. And the HTTP request middleware pipeline is finished. That means the response has been returned from HttpClient.SendAsync or HttpMessageInvoker.SendAsync.

Edit: Potential problem with the idea above. The HttpResponseMessage returned for a request doesn't have to exit pipeline. A handler could decide to create a new one or retry the HTTP request which returns a new response. I added explicitly calling HttpResponseMessage.Dispose as another way to indicate the response is complete, but that doesn't seem like a guaranteed fix because someone might not dispose the original HttpResponseMessage.

API Usage

public void MyDelegatingHandler : DelegatingHandler
{
    public long CompletedRequests { get; private set; }

    public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
    {
        var response = await SendAsync(request);
        response.Completed.Register(() => CompletedRequests++);
        return response;
    }
}

Alternative Designs

No response

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions