HttpClient uses implementations of
HttpMessageHandler to do its job. The
default handler is
There may be a chain of handlers (delegating handler pattern). Messages go
down throug handlers and responses go up to the
HttpClient. Any handler can
decide not to pass message down and return a response earlier (i.e. caching).
Accept header is crucial for the client to be reliable. Server may
default to other formats, like XML, and our app cannot just expect to get JSON.
It needs to explicitly state that in an
Accept header. Even if some endpoint
returns empty content it is still a good practice to set
Accept header, in
case when an error is returned.
Requests can be sent with “shortcut” methods of
but if more customization is required (like custom headers) an
HttpRequestMessage should be used.
The base type of content is
HttpContent. It is abstract. Derived types:
Streams will help with memory usage. However, time might not always improve. Still, memory usage is often of higher priority.
It is recommended to ALWAYS use streams when reading data. When reading the
response’s content, we can use
ReadAsStringAsync(). However, it creates
unnecessary memory allocation for the whole content string, which we need only
for deserialization in most cases. It’s a better idea to use
ReadAsStreamAsync() and deserialize the data from the stream directly.
There is additional perfmance improvement. By default,
HttpClient will return
the response only after the whole content is fetched from the server. We can
instead get the stream while it’s still being fetched:
StreamContent can be used to send body from a stream. Us it when posting large
amounts of data.
It makes sense to use compression when getting data from servers (gzip,
HttpClient has built-in support for it, so that the data gets
decompressed automatically when it is received.
To implement delegating handlers pattern, we should create a class inheriting
Registration of custom handler:
We added just our custom handler, but there is always a default
HttpClientHandler in the end of the pipeline. If we want, we can configure it
Now, first our custom handler will be invoked, and then the primary one with custom configuration.