Подтвердить что ты не робот

Как правильно удалить экземпляр WebResponse?

Как правило, один код записывает что-то вроде этого, чтобы загрузить некоторые данные с помощью WebRequest.

using(WebResponse resp = request.GetResponse())  // WebRequest request...
   using(Stream str = resp.GetResponseStream())  
      ; // do something with the stream str

Теперь, если вызывается WebException, WebException имеет ссылку на объект WebResponse, который может иметь или не иметь Dispose (в зависимости от того, где произошло исключение или как реализуется класс ответа) - я не знать.

Мой вопрос в том, как с этим нужно иметь дело. Предполагается, что кодирование очень защищено, и избавиться от ответа в объекте WebException (это было бы немного странно, поскольку WebException не является IDisposable). Или следует ли игнорировать это, потенциально доступ к расположенному объекту или никогда не удалять объект IDisposable? Пример, приведенный в документации MSDN для WebException.Response полностью неадекватен.

4b9b3361

Ответ 1

Я быстро заглянул в Reflector и теперь могу сказать:

  • WebResponse, являясь абстрактным классом, делегирует все его поведение закрытия/распоряжения своим производным классам.
  • HttpWebResponse, являясь производным классом, который вы почти наверняка используете здесь, в методах close/dispose, касается только удаления фактического потока ответов. Остальная часть состояния класса может быть оставлена ​​на усмотрение GC.

Из этого следует, что, вероятно, безопасно делать все, что угодно, в отношении обработки исключений, если:

  • Когда вы читаете поток ответов из WebResponse в блоке try, заключите его в блок using.
  • Если вы читаете поток ответов из WebException в блоке catch, заключите его также в блок using.
  • Не нужно беспокоиться об утилизации WebException.

Ответ 2

using (var x = GetObject()) {
     statements;
}

(почти) эквивалентно

var x = GetObject();
try {
    statements;
}
finally {
     ((IDisposable)x).Dispose();
}

чтобы ваш объект всегда был удален.

Это означает, что в вашем случае

try {
    using (WebResponse resp = request.GetResponse()) {
        something;
    }
}
catch (WebException ex) {
    DoSomething(ex.Response);
}

ex.Response будет тем же объектом, что и ваш локальный объект resp, который вызывается, когда вы попадаете в обработчик catch. Это означает, что DoSomething использует расположенный объект и, скорее всего, не с ObjectDisposedException.

Ответ 3

Я уверен, что когда у вас есть оператор using, объект находится вне зависимости от того, как вы выходите из блока using (будь то через исключение, возвращаете или просто прогрессируете через функцию).

Я подозреваю, что вы обнаружите, что объект внутри WebException уже был удален, если вы позволите ему оставить блок использования.

Помните, что удаление объекта не обязательно предотвращает его доступ позднее. Это может быть непредсказуемо, чтобы попытаться вызвать методы на нем позже, вызывая исключения из его собственного или очень странного поведения (и, следовательно, я бы не рекомендовал его). Но даже большая часть объекта по-прежнему остается за сборщиком мусора, даже если вы распоряжаетесь им и, следовательно, все еще доступна. Цель dispose - это, как правило, очищать ручки ресурсов (как в этом случае активные TCP-соединения), которые по соображениям производительности вы не можете реально уйти, пока сборщик мусора не найдет их. Я только упоминаю об этом, чтобы уточнить, что он не является взаимоисключающим для его удаления, а исключение - для ссылки на него.

Ответ 4

HttpWebRequest внутренне создает поток памяти из основного сетевого потока, прежде чем бросать WebException, поэтому нет неуправляемого ресурса, связанного с WebResponse, возвращаемым из WebException.Response.

Это делает ненужным вызов Dispose() на нем. На самом деле, попытка избавиться от WebException.Response может вызвать головную боль и проблемы, потому что у вас могут быть абоненты вашего кода, который пытается прочитать связанные с ним свойства.

Однако рекомендуется использовать любые IDisposable объекты, которыми вы владеете. Если вы решите это сделать, убедитесь, что у вас нет защиты кода от возможности читать свойства WebException.Response и/или его поток. Лучшим способом было бы вы справиться с этим исключением и генерировать исключение нового типа, чтобы, по возможности, не утечка WebException до вызывающего.

А также рассмотрим переход к HttpClient, который заменяет HttpWebRequest.

Отказ от ответственности: никаких гарантий не подразумевается.

Ответ 5

Очень интересный вопрос (хотя стоит отметить, что объект WebResponse будет удален при выходе из него). Я чувствую, что на самом деле не имеет значения, что у вас есть ссылка на этот удаленный объект WebResponse, если вы не пытаетесь сделать с ним что-либо "оперативное".

Возможно, вы все равно можете получить доступ к определенным свойствам экземпляра для целей ведения журнала (например, ResponseUri), не получив ObjectDisposedException, но общая ссылка, содержащаяся в исключении, отсутствует, поэтому вы можете продолжать использовать экземпляр.

Мне было бы интересно узнать, что говорят другие.

Ответ 6

Я получаю подобные случаи в соединениях EF DB.

Итак, я действительно создаю список соединений.

В конце игры я loop уничтожает все из них.