Безопасное закрытие и прекращение выпуска ресурсов при удалении сетевых подключений
Пример UsingUsing демонстрирует использование Close
ресурсов и Abort
методов для очистки ресурсов при использовании типизированного клиента. Оператор using
вызывает исключения, если сетевое подключение не является надежным. Этот пример основан на начале работы , который реализует службу калькулятора. В этом образце клиентом является консольное приложение (EXE), а служба размещается в службах IIS.
Примечание.
Процедура настройки и инструкции по построению для данного образца приведены в конце этого раздела.
В этом образце показаны две общие проблемы, которые могут возникнуть при использовании оператора "using" в C# с типизированными клиентами, а также код, который правильно выполняет очистку после исключений.
Оператор "using" в C# приводит к вызову метода Dispose
(). Этот метод эквивалентен методу Close
(), который может выдавать исключения при возникновении сетевой ошибки. Поскольку вызов метода Dispose
() выполняется неявно в закрывающей круглой скобке блока "using", этот источник исключений, скорее всего, останется незамеченным как теми, кто пишет код, так и теми, кто его считывает. Он представляет собой потенциальный источник ошибок приложения.
Первая проблема, показанная в методе DemonstrateProblemUsingCanThrow
, заключается в том, что закрывающая круглая скобка выдает исключение, а код после закрывающей круглой скобки не выполняет следующее.
using (CalculatorClient client = new CalculatorClient())
{
...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");
Даже если ничего в блоке "using" не выдает исключения или все исключения в блоке "using" перехватываются, Console.WriteLine
может не произойти, поскольку неявный вызов метода Dispose
() в закрывающей круглой скобке может выдать исключение.
Вторая проблема, показанная в методе DemonstrateProblemUsingCanThrowAndMask
, представляет собой еще одно последствие использования закрывающей круглой скобки, выдающей исключение.
using (CalculatorClient client = new CalculatorClient())
{
...
throw new ApplicationException("Hope this exception was not important, because "+
"it might be masked by the Close exception.");
} // <-- this line might throw an exception.
Поскольку метод Dispose
() происходит в блоке "finally", исключение ApplicationException
никогда не видно за пределами блока "using", если метод Dispose
() выполняется с ошибкой. Если внешний код должен знать, когда происходит исключение ApplicationException
, конструкция "using" может стать причиной возникновения проблем, маскируя это исключение.
Наконец, в этом образце показано, как правильно выполнить очистку, если исключения происходят в DemonstrateCleanupWithExceptions
. При этом используется блок try/catch для сообщения об ошибках и вызова метода Abort
. Дополнительные сведения о перехвате исключений из вызовов клиентов см. в примере ожидаемых исключений.
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
Примечание.
Оператор using
и ServiceHost
: многие приложения для самостоятельного размещения не делают больше, чем размещение службы, и ServiceHost.Close
редко вызывает исключение, поэтому такие приложения могут безопасно использовать инструкцию using
с ServiceHost
. Однако следует учитывать, что ServiceHost.Close
может вызывать исключение CommunicationException
, поэтому если приложение продолжается после закрытия ServiceHost
, следует избегать инструкции using
и следовать шаблону, заданному ранее.
При выполнении образца ответы и исключения операций отображаются в окне консоли клиента.
Клиентский процесс выполняет три сценария, каждый из которых пытается вызвать метод Divide
. В первом сценарии показан код, пропущенный из-за исключения, выданного методом Dispose
(). Во втором сценарии показано важное исключение с маской из-за исключения, выданного методом Dispose
(). В третьем сценарии показана правильная очистка.
Ниже представлен ожидаемый результат выполнения клиентского процесса.
=
= Demonstrating problem: closing brace of using statement can throw.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating problem: closing brace of using statement can mask other Exceptions.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating cleanup with Exceptions.
=
Calling client.Add(0.0, 0.0);
client.Add(0.0, 0.0); returned 0
Calling client.Divide(0.0, 0.0);
Got System.ServiceModel.CommunicationException from Divide.
Press <ENTER> to terminate client.
Настройка, сборка и выполнение образца
Убедитесь, что вы выполнили процедуру однократной установки для примеров Windows Communication Foundation.
Чтобы создать выпуск решения на языке C# или Visual Basic .NET, следуйте инструкциям в разделе Building the Windows Communication Foundation Samples.
Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в разделе "Примеры Windows Communication Foundation".