views:

384

answers:

1

I use this code snippet that verifies if the file specified in the URL exists and keep trying it every few seconds for every user. Sometimes (mostly when there are large number of users using the site) the code doesn't work.

    [WebMethod()]
    public static string GetStatus(string URL)
    {
        bool completed = false;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            try
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    completed = true;
                }
            }
            catch (Exception)
            {
                //Just don't do anything. Retry after few seconds
            }
        }

        return completed.ToString();
    }

When I look at the Windows Event logs there are several errors:

Unable to read data from the transport connection. An existing connection was forcibly closed

The Operation has timed out

The remote host closed the connection. The error code is 0x800703E3

When I restart the IIS, things work fine until the next time this happens.

+2  A: 

You are putting the try/catch inside the using statement while it's the request.GetResponse method that might throw:

bool completed = false;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
try
{
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    {
        if (response.StatusCode == HttpStatusCode.OK)
        {
            completed = true;
        }
    }
}
catch (Exception)
{
    //Just don't do anything. Retry after few seconds
}
return completed.ToString();
Darin Dimitrov
Can you explain your thinking on why this exception is being thrown? I did read about KeepAlive property that needs to be set to false, but am not sure if I have to do this in this case.
DotnetDude
There are too many possible scenarios when an HTTP request times out.
Darin Dimitrov
In theory, when an HTTP request times out, I'd assume it would simply close the connection. I am not sure why OTHER users are getting affected as soon as one connection is timed out.
DotnetDude
Because ASP.NET uses a thread pool to serve requests and when all the threads in this pool have been exhausted in order to wait for a response from a distant server the web service will no longer be able to accept new requests. For slow requests it is recommended to use async API which relies on IOCP. (example: BeginGetResponse, EndGetResponse)
Darin Dimitrov
Makes sense now. Do I need to add logic in the catch block to force a close/dispose the connection? Or just wrapping it up in try catch is sufficient?
DotnetDude
You already have a `using` statement around disposable objects which will ensure that they will be properly disposed. The `try/catch` is only used to avoid the web method propagating an exception to the caller and return `false` if an error is thrown when accessing the remote URL.
Darin Dimitrov
Like Darin mentioned, you need to handle the exception if you insist on the current design. If I were you I rather give up the current design and do something smarter. For example, only check the URL availability before using it and don't use precious resources too early.
Lex Li
@Lex Li-MSFT: How would I check the URL availability before using it?
DotnetDude
My previous comment means that you need to give up this web method, especially when this one is only used on client side before calling another web method. You should integrate them together.Besides, consider sending out HTTP HEAD requests instead of GET. HEAD responses are smaller, so performance may be better.
Lex Li