6

First, I have ServiceStack as my server which provides RESTful HTTP API.

Here is an example.

public void GET(XXXXXRequest request) { System.Threading.Thread.Sleep(2000); } 

Then I use System.Net.Http.HttpClient to access it. As it is said here, HttpClient is thread-safe for most of its methods to sending HTTP GET requests over the same TCP connection.

So I have a singleton instance of HttpClient as below

HttpClient _httpClient = new HttpClient(new WebRequestHandler() { AllowPipelining = true }); 

Then I use the following test code to send the request one after previous's response

await _httpClient.SendAsync(request1, HttpCompletionOption.ResponseContentRead); await _httpClient.SendAsync(request2, HttpCompletionOption.ResponseContentRead); await _httpClient.SendAsync(request3, HttpCompletionOption.ResponseContentRead); 

In smart sniffer, I do see the requests are sent in one connection and it goes like:

Client -> Request1 Client <- Response1 Client -> Request2 Client <- Response2 Client -> Request3 Client <- Response3 

Now I change the code to fire-and-forget mode as below.

_httpClient.SendAsync(request1, HttpCompletionOption.ResponseContentRead); _httpClient.SendAsync(request2, HttpCompletionOption.ResponseContentRead); _httpClient.SendAsync(request3, HttpCompletionOption.ResponseContentRead); 

So that the requests are sent without waiting for previous reponse and I expect the requests & response go like below

Client -> Request1 Client -> Request2 Client -> Request3 Client <- Response1 Client <- Response2 Client <- Response3 

This is HTTP pipeline and quite good for performance.

enter image description here

But from my test, I see 3 connections are established for each of the HTTP GET request and it does not work as I expected.

Regarding the AllowPipelining proeprty, MSDN says

An application uses the AllowPipelining property to indicate a preference for pipelined connections. When AllowPipelining is true, an application makes pipelined connections to the servers that support them.

So, I suppose HttpClient does support pipelining, and the problem is located in ServiceStack? Is there some options in ServiceStack to enable HTTP pipelining?

2 Answers 2

2

Pipelining is done at a very low level, below IIS even (in the http.sys kernel mode driver). While I'm afraid I can't explain the behavior you're seeing, I can confidently say that ServiceStack is not on the hook for supporting it. It's an HttpHandler, whose only concern is how to process a request and return a response.

Sign up to request clarification or add additional context in comments.

2 Comments

I am using self-host service AppSelfHostBase instead of IIS, I assume it is done via http.sys and HttpListener internally?
Yes. ServiceStack's listener uses System.Net.HttpListener internally.
0

When you use multiple await operators, they are run one after another, so HttpClient is only given one request at a time, and therefore can't use pipelining.

You can use Task.WhenAll() to run multiple tasks in parallel:

var responses = await Task.WhenAll( _httpClient.SendAsync(request1, HttpCompletionOption.ResponseContentRead), _httpClient.SendAsync(request2, HttpCompletionOption.ResponseContentRead), _httpClient.SendAsync(request3, HttpCompletionOption.ResponseContentRead)); var response1 = responses[0]; var response2 = responses[1]; var response3 = responses[2]; 

Notice that only the Task.WhenAll is awaited

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.