Network helper class with retry logic on failure I wrote an helper class which allow me to request the body content from a site that is created by AJAX, for doing so I'm using Puppeteer Sharp. This is the class:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using PuppeteerSharp;

namespace App.Helpers
{
    public class NetworkHelper
    {    
    /// &lt;summary&gt;
    /// Get the html of a page waiting for an AJAX call until the selector is visible.
    /// &lt;/summary&gt;
    /// &lt;param name="url"&gt;Link needed for execute the request.&lt;/param&gt;
    /// &lt;param name="selector"&gt;Selector to wait.&lt;/param&gt;
    /// &lt;param name="attempts"&gt;Max attempts until request fail.&lt;/param&gt;
    /// &lt;returns&gt;Contains the html of the requested page.&lt;/returns&gt;
    public static async Task&lt;string&gt; LoadAndWaitForSelector(Uri url, string selector, int attempts = 5)
    {
        try
        {
            //Create new browser page
            using (Page page = await Handler.Browser.NewPageAsync())
            {                        
                //Navigate on the requested content and wait for selector
                await page.GoToAsync(url.ToString(), timeout: 0);
                await page.WaitForSelectorAsync(selector); //may throw error for timeout    
                return await page.GetContentAsync();
            }
        }
        catch (WaitTaskTimeoutException)
        {
            //there are other attempts, rerty
            if (attempts != 0)
            {
                attempts--;

                //add some delay
                await Task.Delay(10000);

                return await LoadAndWaitForSelector(url, selector, attempts);
            }
            throw;
        }
    }
}


Question: Could this class be improved more?

Also, the Browser is static, so each instance use the same browser for avoid memory leak:

public static Browser Browser { get; set; }


the method is called in the following way:

var html = await NetworkHelper.LoadAndWaitForSelector(
            new Uri("some url"), "#archive-tables");


thanks.
Just wanted to add that you may want to consider using Polly instead of rolling your own retry mechanism - this is a library built specifically for this kind of retry mechanism (as well as many more complicated scenarios). Using Polly would look something like the following.

Note that I have renamed the attempts parameter to retryAttempts to make it clear that this does not define the total number of attempts but rather the total number of retry attempts after the initial one, to keep the behaviour the same as your sample code.

public class NetworkHelper
{
    public static Task&lt;string&gt; LoadAndWaitForSelectorAsync(
        Uri url, string selector, int retryAttempts = 5)
    {
        // Create a policy that will...
        var policy = Policy
            // Retry for any `WaitTaskTimeoutException` raised during execution.
            .Handle&lt;WaitTaskTimeoutException&gt;()
            .WaitAndRetryAsync(
                // Retry the specified number of times after the initial attempt.
                retryCount: retryAttempts,
                // Wait for the given duration between each retry attempt. Note that
                // this can depend on the retry number if required.
                sleepDurationProvider: retryNumber =&gt; TimeSpan.FromSeconds(10));

        // Execute the operation to get the selector within the retry policy. If the
        // final retry attempt does not succeed, the resulting `WaitTaskTimeoutException`
        // will not be handled by the policy and will be thrown.
        return policy.ExecuteAsync(() =&gt; TryGetSelectorAsync(url, selector));
    }

    private static async Task&lt;string&gt; TryGetSelectorAsync(Uri url, string selector)
    {
        using (Page page = await Handler.Browser.NewPageAsync())
        {
            await page.GoToAsync(url.ToString(), timeout: 0);
            await page.WaitForSelectorAsync(selector);
            return await page.GetContentAsync();
        }
    }
}