Guerrilla
Guerrilla

Reputation: 14926

Set timeout with HttpClientHandler

I am trying to set the timeout value of anglesharp.io using HttpClientHandler.

This issue suggests it is possible: https://github.com/AngleSharp/AngleSharp/issues/266

I am getting page like this:

        NetworkCredential proxyCreds = new NetworkCredential(proxy.User, proxy.Pass);

        WebProxy wProxy = new WebProxy(proxy.Ip + ":" + proxy.Port, false)
        {
            UseDefaultCredentials = false,
            Credentials = proxyCreds,
        };

        HttpClientHandler httpClientHandler = new HttpClientHandler()
        {
            Proxy = wProxy,
            PreAuthenticate = true,
            UseDefaultCredentials = false
        };

        var config = Configuration.Default.WithRequesters(httpClientHandler);

        var document = await BrowsingContext.New(config).OpenAsync(address);

I cannot see any properties available to set the timeout. How do I set the timeout?

Upvotes: 1

Views: 7869

Answers (2)

Florian Rappl
Florian Rappl

Reputation: 3189

The comments above are right. AngleSharp is abstracting requesters away - to allow multiple types of requesters and provide flexibility if needed. The essential interface is IRequester (note: there is no HTTP on purpose - in AngleSharp.Io we also find, e.g., a FileRequester that accesses the local file system for file:// URIs).

We could now either implement our own requester or just use the HttpClientRequester from AngleSharp.Io with the constructor overload accepting an HttpClient instance.

var client = new HttpClient();
client.Timeout = MyCustomTimeout; //Whatever value you want it to be
var requester = new HttpClientRequester(client);

Now the question is how can you use this requester? We just create a configuration (as usual) and use the default loader extension method (as usual), however, this time with our custom requester.

For pre 0.10 this looks as follows:

 // Assumes we do not want to provide custom options for the loaders
 var requesters = new [] { requester };
 var configuration = Configuration.Default.WithDefaultLoader(requesters: requesters);

For 0.10 and later this looks a bit different:

 var configuration = Configuration.Default.WithRequester(requester).WithDefaultLoader();

Hope this helps!

Upvotes: 2

stop-cran
stop-cran

Reputation: 4408

Sometimes it's needed to have different timeouts on the level of HttpClient and HttpClientHandler, for example kind of retry logic, seamless for HttpClient - wait for 5 minutes, but retry every minute. In this case one can use a delegating handler like following:

public class RetryHandler : DelegatingHandler
{
    private readonly TimeSpan timeout;

    public RetryHandler(TimeSpan timeout)
    {
        this.timeout = timeout;
    }

    private async Task<HttpResponseMessage> Delay(
        CancellationToken cancellationToken)
    {
        await Task.Delay(timeout, cancellationToken);

        return null;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        for (; ; )
        {
            cancellationToken.ThrowIfCancellationRequested();

            var delayTask = Delay(cancellationToken);
            var firstCompleted = await Task.WhenAny(
                base.SendAsync(request, cancellationToken), delayTask);

            if (firstCompleted != delayTask)
                return await firstCompleted;
        }
    }
}

Use case:

var client = new HttpClient(
new RetryHandler(TimeSpan.FromMinutes(1)))
{
    Timeout = TimeSpan.FromMinutes(5)
};

client.PostAsync(...);

Upvotes: 0

Related Questions