Udostępnij za pośrednictwem


Bezpieczne zamykanie i przerywanie wydawania zasobów po usunięciu połączeń sieciowych

W przykładzie UsingUsing pokazano, jak używać Close metod i Abort do czyszczenia zasobów podczas korzystania z typizowanego klienta. Instrukcja using powoduje wyjątki, gdy połączenie sieciowe nie jest niezawodne. Ten przykład jest oparty na wprowadzenie , który implementuje usługę kalkulatora. W tym przykładzie klient jest aplikacją konsolową (.exe), a usługa jest hostowana przez usługi Internet Information Services (IIS).

Uwaga

Procedura instalacji i instrukcje kompilacji dla tego przykładu znajdują się na końcu tego tematu.

W tym przykładzie przedstawiono dwa typowe problemy występujące podczas korzystania z instrukcji "using" języka C# z typowymi klientami, a także kod, który poprawnie czyści się po wyjątkach.

Instrukcja "using" języka C# powoduje wywołanie metody Dispose(). Jest to takie samo jak Close(), które mogą zgłaszać wyjątki w przypadku wystąpienia błędu sieciowego. Ponieważ wywołanie metody Dispose() odbywa się niejawnie na zamykającym nawiasie klamrowym bloku "using", to źródło wyjątków może być niezauważone zarówno przez osoby piszące kod, jak i odczytując kod. Reprezentuje to potencjalne źródło błędów aplikacji.

Pierwszy problem, zilustrowany w metodzie DemonstrateProblemUsingCanThrow , polega na tym, że nawias klamrowy zamykający zgłasza wyjątek, a kod po zamykającym nawiasie klamrowym nie jest wykonywany:

using (CalculatorClient client = new CalculatorClient())
{
    ...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");

Nawet jeśli żadne elementy wewnątrz bloku using zgłasza wyjątek lub wszystkie wyjątki wewnątrz bloku using są przechwytywane, przyczyną może się nie zdarzyć, Console.WriteLine ponieważ niejawne Disposewywołanie () przy zamykającym nawiasie klamrowym może zgłosić wyjątek.

Drugi problem, zilustrowany w metodzie DemonstrateProblemUsingCanThrowAndMask , jest kolejnym implikacją zamykającego nawiasu klamrowego zgłaszającego wyjątek:

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.

Ponieważ element Dispose() występuje wewnątrz bloku "finally", obiekt nigdy nie jest widoczny poza blokiem użycia, ApplicationException jeśli Dispose() zakończy się niepowodzeniem. Jeśli kod na zewnątrz musi wiedzieć o tym, kiedy ApplicationException wystąpi, konstrukcja "using" może powodować problemy przez maskowanie tego wyjątku.

Na koniec w przykładzie pokazano, jak prawidłowo wyczyścić, gdy wystąpią wyjątki w pliku DemonstrateCleanupWithExceptions. Spowoduje to użycie bloku try/catch w celu zgłaszania błędów i wywoływania metody Abort. Zobacz przykład Oczekiwane wyjątki, aby uzyskać więcej informacji na temat przechwytywania wyjątków z wywołań klienta.

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

Uwaga

Instrukcja using i ServiceHost: Wiele aplikacji do samoobsługowego hostingu robi niewiele więcej niż hostowanie usługi, a ServiceHost.Close rzadko zgłasza wyjątek, więc takie aplikacje mogą bezpiecznie używać instrukcji using z ServiceHost. Należy jednak pamiętać, że element ServiceHost.Close może zgłosić wartość CommunicationException, więc jeśli aplikacja będzie kontynuowana po zamknięciu obiektu ServiceHost, należy unikać instrukcji using i postępować zgodnie ze wzorcem podanym wcześniej.

Po uruchomieniu przykładu odpowiedzi i wyjątki operacji są wyświetlane w oknie konsoli klienta.

Proces klienta uruchamia trzy scenariusze, z których każda próbuje wywołać metodę Divide. Pierwszy scenariusz demonstruje pomijanie kodu z powodu wyjątku od Dispose(). Drugi scenariusz demonstruje ważny wyjątek maskowany z powodu wyjątku ( Dispose). Trzeci scenariusz pokazuje prawidłowe czyszczenie.

Oczekiwane dane wyjściowe z procesu klienta to:

=
= 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.

Aby skonfigurować, skompilować i uruchomić przykład

  1. Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.

  2. Aby skompilować wersję rozwiązania w języku C# lub Visual Basic .NET, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).

  3. Aby uruchomić przykład w konfiguracji pojedynczej lub między maszynami, postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.