Не удается получить ResponseStream из WebException

У меня есть настольный клиент, который общается с сервером через Http. Когда у сервера возникают проблемы с обработкой данных, он возвращает описание ошибки в JSON в теле ответа Http с правильным Http-кодом (в основном это HTTP-400).

Когда я читаю ответ HTTP-200, все хорошо, и этот код работает:

 using (var response = await httpRequest.GetResponseAsync(token))
                {
                    using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
                    {
                        return await reader.ReadToEndAsync();
                    }
                }

Но когда происходит ошибка, и WebException генерируется и перехватывается, появляется следующий код:

 catch (WebException ex)
            {
                 if (ex.Status == WebExceptionStatus.ProtocolError)
                {                   
                    using (var response = (HttpWebResponse) ex.Response)
                    {
                        using (var stream = response.GetResponseStream())
                        {
                            using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
                            {
                                var json = reader.ReadToEnd();
                            }
                        }
                    }
                }
            }

Я уже сделал что-то с этим, чтобы, возможно, заставить его работать, но происходит следующее:response.ContentLength действителен (184), но stream.Length 0 и после этого я не могу читать JSON (это "") Я даже не знаю, где искать, потому что все выглядит так, как будто оно должно работать.

В чем может быть проблема?

2 ответа

Решение

После месяца почти каждодневных размышлений я нашел обходной путь.

Дело в том, что WebException.Response.GetResponseStream() возвращает не совсем тот же поток, который был получен во время запроса (сейчас мы не можем найти ссылку на msdn), и к тому времени, когда мы получим перехватить исключение и прочитать этот поток, реальный поток ответа теряется (или что-то в этом роде, я действительно знал и не смог найти какую-либо информацию в сети, кроме как заглянуть в CLRCore, который сейчас является открытым.

Сохранить фактический ответ до отлова WebException вы должны установить KeepAlive Недвижимость на вашем HttpRequest и вуаля, вы получите свой ответ, ловя исключение. Итак, рабочий код выглядит так:

            try
            {
                var httpRequest = WebRequest.CreateHttp(Protocol + ServerUrl + ":" + ServerPort + ServerAppName + url);

                if (HttpWebRequest.DefaultMaximumErrorResponseLength < int.MaxValue)
                    HttpWebRequest.DefaultMaximumErrorResponseLength = int.MaxValue;

                httpRequest.ContentType = "application/json";
                httpRequest.Method = method;
                var encoding = Encoding.GetEncoding("utf-8");

                if (httpRequest.ServicePoint != null)
                {
                    httpRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
                    httpRequest.ServicePoint.MaxIdleTime = 5000;
                }
                //----HERE--
                httpRequest.KeepAlive = true;
                //----------
                using (var response = await httpRequest.GetResponseAsync(token))
                {
                    using (var reader = new StreamReader(response.GetResponseStream(), encoding))
                    {                       
                        return await reader.ReadToEndAsync();
                    }
                }
            }
            catch (WebException ex)
            {
                if (ex.Status == WebExceptionStatus.ProtocolError)
                {
                    using (var response = (HttpWebResponse)ex.Response)
                    {
                        using (var stream = response.GetResponseStream())
                        {
                            using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
                            {
                                return reader.ReadToEnd();
                                //or handle it like you want
                            }
                        }
                    }
                }
            }

Я не знаю, хорошо ли поддерживать такое соединение, но так как это помогло мне прочитать реальные ответы с сервера, я думаю, что это может помочь кому-то, кто столкнулся с той же проблемой.

РЕДАКТИРОВАТЬ: Также важно не связываться с HttpWebRequest.DefaultMaximumErrorResponseLength,

Я помню, как сталкивался с подобной проблемой раньше, и было нечто, связанное с настройкой позиции потока. Вот одно из моих решений для чтения webResponse, которое работало для меня ранее. Пожалуйста, попробуйте, если подобный подход работает для вас:-

private ResourceResponse readWebResponse(HttpWebRequest webreq)
    {
        HttpWebRequest.DefaultMaximumErrorResponseLength = 1048576;
        HttpWebResponse webresp = null;// = webreq.GetResponse() as HttpWebResponse;
        var memStream = new MemoryStream();
        Stream webStream;
            try
            {
                webresp = (HttpWebResponse)webreq.GetResponse();
                webStream = webresp.GetResponseStream();
                byte[] readBuffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = webStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                    memStream.Write(readBuffer, 0, bytesRead);
            }
            catch (WebException e)
            {
                var r = e.Response as HttpWebResponse;
                webStream = r.GetResponseStream();
                memStream = Read(webStream);
                var wrongLength = memStream.Length;
            }


            memStream.Position = 0;
            StreamReader sr = new StreamReader(memStream);
            string webStreamContent = sr.ReadToEnd();

            byte[] responseBuffer = Encoding.UTF8.GetBytes(webStreamContent);
//......
//.......

Надеюсь это поможет!

Другие вопросы по тегам