Зависает программа. C#

187
06 марта 2019, 06:00

Имеется программа. Периодически зависает, не помогает ничего, т.е. только перезапуск. Место зависание в функции отправки запроса.

public async Task<string> PostRequestAsync(string url, string PostData, string Referer, CancellationToken ct)
{
    string Answer;
    ct.ThrowIfCancellationRequested();
    HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(url);
    if (Proxy != null)
    {
        Request.Proxy = Proxy;
    }
    else
    {
        Request.Proxy = null;
    }
    Request.Method = "POST";
    Request.KeepAlive = true;
    Request.Timeout = 10000;
    Request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    Request.Host = BaseUrl.Substring(8);
    Request.KeepAlive = true;
    byte[] bytes = Encoding.UTF8.GetBytes(PostData);
    Request.ContentLength = bytes.Length;
    Request.Accept = "text/html, */*; q=0.01";
    Request.Headers.Add($"Origin: {BaseUrl}");
    Request.Headers.Add("X-Requested-With: XMLHttpRequest");
    Request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.168 Safari/537.36 OPR/51.0.2830.40";
    Request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
    Request.Referer = Referer;
    Request.Headers.Add("Accept-Encoding: gzip, deflate, br");
    Request.Headers.Add("Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7");
    Request.CookieContainer = LoginData;
    try
    {
        ct.ThrowIfCancellationRequested();
        using (Stream stream = await Request.GetRequestStreamAsync())
        {
            stream.Write(bytes, 0, bytes.Length);
        }
        WebResponse Response = await Request.GetResponseAsync();
        ct.ThrowIfCancellationRequested();
        using (StreamReader streamReader = new StreamReader(Response.GetResponseStream()))
        {
            Answer = await streamReader.ReadToEndAsync();
        }
        if (Answer.Contains("\\/site\\/logIn"))
        {
            Answer = "1";
            string html = await GetClearRequestAsync(BaseUrl, ct);
            var parser = new HtmlParser();
            var document = parser.Parse(html);
            string name = document.GetElementById("authentification").Children[1].GetAttribute("name").ToLower();
            string value = document.GetElementById("authentification").Children[1].GetAttribute("value").ToLower();
            string PostData1 = $"{name}={value}&login={login}&password={password}&redirection=&isBoxStyle=";
            await LoginRequestAsync(PostData1, ct);
        }
        Request.Abort();
        Response.Close();
    }
    catch
    {
        Request.Abort();
        Answer = "0";
    }
    return Answer;
}

Пытался разбираться в сути проблемы. Было выявлено, что наиболее часто происходит такая проблема в двух случаях: а) Плохое соединение с интернетом б) Слабый ПК (ещё не совсем потверждено) Случай "а" пытался исправить путем добавление цикла do while с проверкой на положительный ответ от сервера. Не вышло. Была мысль, что это связано с бесконечными попытками открытия соединения и добавил проверку такого рода

if(System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())

Тоже мимо. Теперь встал в тупик как же выявлять и присекать подобные случаи. Можно заметить что в функцию передается Cancellationtoken, отменить работу программы с его помощью не удаётся.

P.S. Работа возможно только с HttpWebRequest, остальные средства либо не подходят по удобству реализации, либо некорректно работают с сервером, стабильности добился только при таком подходе.

Answer 1

В вашем коде трудно разобраться, но выглядит как будто вы никак не используете CancellationToken и не реализуете таймаут для сетевых операций. Для асинхронных сетевых операций, в отличие от синхронных, Request.Timeout играет роль только на начальном этапе от отправки заголовка до получения первых байт ответа. При обрыве связи на последующей загрузке они просто тихо умирают (никогда не заканчиваются), поэтому таймаут нужно реализовать вручную, как-то так:

static async Task<string> Download(string url)
{            
        HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(url);
        var resp = await Request.GetResponseAsync();
        var stream = resp.GetResponseStream();
        MemoryStream ms = new MemoryStream();
        using (stream)
        using (ms)
        {
            await stream.CopyToAsync(ms);
            ms.Seek(0, SeekOrigin.Begin);
            var rd = new System.IO.StreamReader(ms);
            return await rd.ReadToEndAsync();
        }            
}
private async void button1_Click(object sender, EventArgs e)
{
    const string url = "http://example.com/";                    
    var res = await Task.WhenAny(Download(url),Task.Delay(10000));
    if (res is Task<string>) textBox1.Text = (res as Task<string>).Result;
    else textBox1.Text = "Timeout expired!";
}
READ ALSO
Удаление(Destroy) GameObject не работает

Удаление(Destroy) GameObject не работает

Есть проект на unityСуть в том, что при подгрузки нового(второго) уровня из префаба старый(первый) уровень с тегом Level я должен удалить

184
Подключение GetComponent&lt;Renderer&gt;()

Подключение GetComponent<Renderer>()

Прохожу уроки по Unity и столкнулся с такой проблемой:

168
Получение данных из COM порта в Unity

Получение данных из COM порта в Unity

стоит задача получения данных из COM портаНаписал код на C# для консольного приложения прямо по инструкции на MSDN и всё замечательно работает

165