Fire & Forget using WebClient by setting Tmeout

I have a question regarding WebClient and I was hoping someone could help me. I know this question has been asked several times, but I couldn't find a good answer.

I have two different scenarios where I need to call a URL. a) I don't need a response from a url (Fire & Forget). b) The url is returning JSON, so I need to wait for the server to finish processing to get my data.

I have some problems with a) and I have no idea that what I did make sense. To implement Fire & Forget, Im setting the WebClient timeout to "small" number, 500 milliseconds (code below). My questions:

a) Is this a good approach or doesn't it make any sense? b) Does it even make sense to wait 500 ms? Can I set the timeout to zero? c) Is this approach safe? I don't care how long it takes to process, but I want to make sure that I can start the web service. Does the code below provide a guarantee that the web service will start, and if not, I get an exception that is not Timneout?

Thank you so much!

public static void SubmitUrl(string url)
{
    using (WebClient webClient = new WebClientEx(500))
    {
        try
        {
            Logger.Log(string.Format("Start Invoking URL: {0}", url));
            var response = webClient.OpenRead(url);
            response.Close();
            Logger.Log(string.Format("End Invoking URL: {0}", url));

        }
        catch (System.Net.WebException ex)
        {
            if (ex.Status != WebExceptionStatus.Timeout)
            {
                Logger.Log(string.Format("Exception Invoking URL: {0} \n {1}", url, ex.ToString()));
                throw;
            }
        }
        catch (System.Exception ex)
        {
            Logger.Log(string.Format("Exception Invoking URL: {0} \n {1}", url, ex.ToString()));
            throw;
        }
    }
}

public class WebClientEx : WebClient
{
    // Timeout in milliseconds
    public int timeout { get; set; }

    public WebClientEx(int timeout)
        : base()
    {
        this.timeout = timeout;
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest wr = base.GetWebRequest(address);
        wr.Timeout = this.timeout;
            return wr;
        }
    }
}

      

+3


source to share


2 answers


I would advise you to use the threadpool again to work with the IO communication, there is simply no need as the thread will spend most of its time on the http request.

Moreover, disabling new threads inside ASP.NET without registering yhem is dangerous and can cause your thread to terminate unexpectedly when reusing the application pool.

I recommend that you study the class HttpClient

and use `async-await.

I would also suggest using fire again and forgetting in most scenarios. What happened if the request failed or threw an exception? Should it be at least registered?



I would go for something like this:

private static async Task SubmitUrlAsync(string url)
{
    try
    {
        var httpClient = new HttpClient();
        Logger.Log(string.Format("Start Invoking URL: {0}", url));

        await httpClient.GetAsync(url);

        Logger.Log(string.Format("End Invoking URL: {0}", url));
    }
    catch (WebException ex)
    {
        if (ex.Status != WebExceptionStatus.Timeout)
        {
            Logger.Log(string.Format("Exception Invoking URL: 
                                {0} \n {1}", url, ex.ToString()));
            throw;
        }
    }
    catch (Exception ex)
    {
        Logger.Log(string.Format("Exception Invoking URL: 
                            {0} \n {1}", url, ex.ToString()));
        throw;
    }
}

      

The keyword await

will return the thread back to the threadpool to handle more requests until this method is executed, and will also propagate any exception thrown by the expected string.

+2


source


Place the WebClient call on a different thread so that it doesn't block anything on your main application thread. In this case, the Logger must be thread safe.



    public static void SubmitUrl(string url)
    {
        Task.Factory.StartNew(() => SubmitUrlPrivate(url));
    }

    private static void SubmitUrlPrivate(string url)
    {
        using (var webClient = new WebClient())
        {
            try
            {
                Logger.Log(string.Format("Start Invoking URL: {0}", url));
                using (webClient.OpenRead(url))
                {
                    Logger.Log(string.Format("End Invoking URL: {0}", url));
                }
            }
            catch (WebException ex)
            {
                if (ex.Status != WebExceptionStatus.Timeout)
                {
                    Logger.Log(string.Format("Exception Invoking URL: {0} \n {1}", url, ex.ToString()));
                    throw;
                }
            }
            catch (Exception ex)
            {
                Logger.Log(string.Format("Exception Invoking URL: {0} \n {1}", url, ex.ToString()));
                throw;
            }
        }
    }

      

+3


source







All Articles