简体   繁体   中英

Httpwebrequest Post Call Timeout is not working

When the IP is right I don't see any issues , but when the IP is down the timeout value is not working and it takes 75 secs or 80 secs to timeout..... The same code without proxy is able to timeout in 15 secs which is the value i set it.

Is this proxy level limitation or any coding issue...I have done lot of research on this and tried many things from Google but no help..

This is my code

{
    HttpWebRequest ObjHttpWebRequest = null;
    HttpWebResponse objHttpWebResponse = null;
    Stopwatch watch = new Stopwatch();
    string strReturn = string.Empty;
    string validUrl = "false";
    try
    {
        watch.Start();
        string DATA = "postdata";
        ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(MyCertValidationCb);
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
        ObjHttpWebRequest = (HttpWebRequest)WebRequest.Create("https://196.234.502.247:4510/path");
        ObjHttpWebRequest.Timeout = 15000;
        ObjHttpWebRequest.Method = "POST";
        ObjHttpWebRequest.ContentType = "application/json";
        ObjHttpWebRequest.ContentLength = DATA.Length;
        {
            WebProxy proxy = new WebProxy();
            proxy.Address = new Uri("http://proxy.com");
            proxy.UseDefaultCredentials = true;
            ObjHttpWebRequest.Proxy = proxy;
        }
        X509Certificate2 X509cert2_client = new X509Certificate2(HttpContext.Current.Request.PhysicalApplicationPath + @"\folder\test.pfx", "test");
        ObjHttpWebRequest.ClientCertificates.Add(X509cert2_client);

        byte[] byteArray = Encoding.UTF8.GetBytes(DATA);
        ObjHttpWebRequest.ContentLength = byteArray.Length;
        Stream objRequestStream = ObjHttpWebRequest.GetRequestStream();
        objRequestStream.Write(byteArray, 0, byteArray.Length);
        objRequestStream.Close();

        using (objHttpWebResponse = ObjHttpWebRequest.GetResponse() as HttpWebResponse)
        {
            using (var objResponseStream = objHttpWebResponse.GetResponseStream())
            {
                using (var objResponseStreamReader = new StreamReader(objResponseStream, Encoding.UTF8))
                {
                    strReturn = objResponseStreamReader.ReadToEnd();
                    objResponseStreamReader.Close();
                }
                objResponseStream.Close();
            }
            objHttpWebResponse.Close();
        }
    }
    catch (Exception ex)
    {
        HttpContext.Current.Response.Write(ex.Message);
    }
    finally
    {
        watch.Stop();
        if (ObjHttpWebRequest != null) ObjHttpWebRequest.Abort();
        if (objHttpWebResponse != null) objHttpWebResponse.Close();
        HttpContext.Current.Response.Write(strReturn+ "--"+ watch.Elapsed.TotalSeconds.ToString()+"__"+ validUrl);
    }
}

According to the MSDN Documentation the usage of a host name could lead to timeout problems:

A Domain Name System (DNS) query may take up to 15 seconds to return or time out. If your request contains a host name that requires resolution and you set Timeout to a value less than 15 seconds, it may take 15 seconds or more before a WebException is thrown to indicate a timeout on your request.

Im not sure that this is the original problem and I would try to identitfy it either way, but you could still implement the timeout yourself to get it working:

byte[] byteArray = Encoding.UTF8.GetBytes(DATA);
ObjHttpWebRequest.ContentLength = byteArray.Length;

var cancelSource = new CancellationTokenSource();
var requestHandlingTask = DoRequestHandling(ObjHttpWebRequest, byteArray, cancelSource.Token);

if (await Task.WhenAny(requestHandlingTask, Task.Delay(TIMEOUT)) == requestHandlingTask)
{
    // The task completed inside the timeout
    strReturn = requestHandlingTask.Result;
}
else
{
    // Timeout handling
    cancelSource.Cancel();

    // ...
}

Inside the request handling we check against the cancellation token whenever we have the possibility (the method calls will still run longer) and cancel the rest of the operation while the main logic can already continue on another thread.

static async Task<string> DoRequestHandling(HttpWebRequest request, byte[] arrByteData, CancellationToken cancelToken)
{
    string strReturn = String.Empty;

    var requestStream = await request.GetRequestStreamAsync()
        .ConfigureAwait(false);

    if (!cancelToken.IsCancellationRequested)
    {
        requestStream.Write(arrByteData, 0, arrByteData.Length);
        requestStream.Close();

        if (!cancelToken.IsCancellationRequested)
        {
            using (var response = await request.GetResponseAsync().ConfigureAwait(false) as HttpWebResponse)
            using (var responseStream = response.GetResponseStream())
            using (var responseStreamReader = new StreamReader(responseStream, Encoding.UTF8))
            {
                strReturn = await responseStreamReader.ReadToEndAsync()
                    .ConfigureAwait(false);
            }
        }
        else
        {
            // Request was cancelled -> exit
        }
    }
    else
    {
        // Request was cancelled -> exit
    }

    return strReturn;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM