Vermeiden von Problemen mit der Using-AnweisungAvoiding Problems with the Using Statement

In diesem Beispiel wird veranschaulicht, wie Sie die C#-Anweisung "using" beim Verwenden eines typisierten Clients nicht zum automatischen Bereinigen von Ressourcen verwenden sollten.This sample demonstrates how you should not use the C# "using" statement to automatically clean up resources when using a typed client. Dieses Beispiel basiert auf der Einstieg , implementiert einen rechnerdienst.This sample is based on the Getting Started that implements a calculator service. In diesem Beispiel ist der Client eine Konsolenanwendung (.exe), und der Dienst wird von IIS (Internet Information Services, Internetinformationsdienste) gehostet.In this sample, the client is a console application (.exe) and the service is hosted by Internet Information Services (IIS).

Hinweis

Die Setupprozedur und die Buildanweisungen für dieses Beispiel befinden sich am Ende dieses Themas.The setup procedure and build instructions for this sample are located at the end of this topic.

In diesem Beispiel werden zwei häufige Probleme veranschaulicht, die beim Verwenden der C#-Anweisung "using" mit typisierten Clients auftreten. Außerdem wird Code bereitgestellt, mit dem die Bereinigung nach Ausnahmen korrekt ausgeführt werden kann.This sample shows two of the common problems that occur when using the C# "using" statement with typed clients, as well as code that correctly cleans up after exceptions.

Die C#-Anweisung "using" führt zu einem Aufruf von Dispose().The C# "using" statement results in a call to Dispose(). Dies ist das Gleiche wie Close(). Dies kann zu Ausnahmen führen, wenn ein Netzwerkfehler auftritt.This is the same as Close(), which may throw exceptions when a network error occurs. Da der Aufruf von Dispose() implizit an der schließenden Klammer des "using"-Blocks erfolgt, wird diese Quelle für Ausnahmen beim Schreiben oder Lesen des Codes häufig nicht bemerkt.Because the call to Dispose() happens implicitly at the closing brace of the "using" block, this source of exceptions is likely to go unnoticed both by people writing the code and reading the code. Dies stellt eine potenzielle Quelle für Anwendungsfehler dar.This represents a potential source of application errors.

Das erste Problem (in der DemonstrateProblemUsingCanThrow-Methode dargestellt) liegt darin, dass die schließende Klammer eine Ausnahme auslöst und der Code nach der schließenden Klammer nicht ausgeführt wird:The first problem, illustrated in the DemonstrateProblemUsingCanThrow method, is that the closing brace throws an exception and the code after the closing brace does not execute:

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

Selbst wenn nichts im using-Block eine Ausnahme auslöst oder alle Ausnahmen im using-Block abgefangen werden, wird Console.Writeline möglicherweise nicht ausgeführt, da der implizite Dispose()-Aufruf an der schließenden Klammer eine Ausnahme auslösen kann.Even if nothing inside the using block throws an exception or all exceptions inside the using block are caught, the Console.Writeline might not happen because the implicit Dispose() call at the closing brace might throw an exception.

Das zweite Problem (in der DemonstrateProblemUsingCanThrowAndMask-Methode veranschaulicht) ist eine weitere Implikation der schließenden Klammer, die eine Ausnahme auslöst:The second problem, illustrated in the DemonstrateProblemUsingCanThrowAndMask method, is another implication of the closing brace throwing an exception:

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.  

Da Dispose() in einem "finally"-Block auftritt, tritt ApplicationException nur außerhalb des using-Blocks auf, wenn bei Dispose() ein Fehler auftritt.Because the Dispose() occurs inside a "finally" block, the ApplicationException is never seen outside the using block if the Dispose() fails. Wenn der Code außen wissen muss, wann die ApplicationException auftritt, kann das "using"-Konstrukt zu Problemen führen, da diese Ausnahme maskiert wird.If the code outside must know about when the ApplicationException occurs, the "using" construct may cause problems by masking this exception.

Abschließend wird im Beispiel veranschaulicht, wie die Bereinigung ordnungsgemäß ausgeführt wird, nachdem Ausnahmen in DemonstrateCleanupWithExceptions aufgetreten sind.Finally, the sample demonstrates how to clean up correctly when exceptions occur in DemonstrateCleanupWithExceptions. Dabei wird ein try/catch-Block verwendet, um Fehler zu melden und Abort aufzurufen.This uses a try/catch block to report errors and call Abort. Finden Sie unter der Ausnahmen erwartet ausführliche Informationen zum Abfangen von Ausnahmen von Clientaufrufe Sample.See the Expected Exceptions sample for more details about catching exceptions from client calls.

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

Hinweis

Die using-Anweisung und ServiceHost: Viele selbst gehostete Anwendungen führen wenige andere Aktionen als das Hosten eines Diensts aus, und ServiceHost.Close löst selten Ausnahmen aus. In solchen Anwendungen kann die using-Anweisung mit ServiceHost daher sicher verwendet werden.The using statement and ServiceHost: Many self-hosting applications do little more than host a service, and ServiceHost.Close rarely throws an exception, so such applications can safely use the using statement with ServiceHost. Achten Sie jedoch darauf, dass ServiceHost.Close eine CommunicationException auslösen kann. Wenn die Anwendung daher nach dem Schließen von ServiceHost fortgesetzt wird, sollten Sie die Verwendung der using-Anweisung vermeiden und sich an das zuvor beschriebene Muster halten.However, be aware that ServiceHost.Close can throw a CommunicationException, so if your application continues after closing the ServiceHost, you should avoid the using statement and follow the pattern previously given.

Wenn Sie das Beispiel ausführen, werden die Antworten und Ausnahmen für den Vorgang im Konsolenfenster des Clients angezeigt.When you run the sample, the operation responses and exceptions are displayed in the client console window.

Im Clientprozess werden drei Szenarios ausgeführt, die jeweils versuchen, Divide aufzurufen.The client process runs three scenarios, each of which attempts to call Divide. Im ersten Szenario wird veranschaulicht, dass Code aufgrund einer Ausnahme von Dispose() übersprungen wird.The first scenario demonstrates code being skipped because of an exception from Dispose(). Im zweiten Szenario wird veranschaulicht, dass eine wichtige Ausnahme aufgrund einer Ausnahme von Dispose() maskiert wird.The second scenario demonstrates an important exception being masked because of an exception from Dispose(). Das dritte Szenario zeigt die ordnungsgemäße Bereinigung.The third scenario demonstrates correct clean up.

Die erwartete Ausgabe vom Clientprozess lautet wie folgt:The expected output from the client process is:

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

So können Sie das Beispiel einrichten, erstellen und ausführenTo set up, build, and run the sample

  1. Stellen Sie sicher, dass Sie ausgeführt haben die Setupprozedur für die Windows Communication Foundation-Beispiele zum einmaligen.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Um die C#- oder Visual Basic .NET-Edition der Projektmappe zu erstellen, befolgen Sie die unter Building the Windows Communication Foundation Samplesaufgeführten Anweisungen.To build the C# or Visual Basic .NET edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Um das Beispiel in einer einzelnen oder computerübergreifenden Konfiguration ausführen möchten, folgen Sie den Anweisungen Ausführen der Windows Communication Foundation-Beispiele.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Wichtig

Die Beispiele sind möglicherweise bereits auf dem Computer installiert.The samples may already be installed on your machine. Suchen Sie nach dem folgenden Verzeichnis (Standardverzeichnis), bevor Sie fortfahren.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Wenn dieses Verzeichnis nicht vorhanden ist, fahren Sie mit Windows Communication Foundation (WCF) und Windows Workflow Foundation (WF) Samples for .NET Framework 4 aller Windows Communication Foundation (WCF) herunterladen und WFWF Beispiele.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WFWF samples. Dieses Beispiel befindet sich im folgenden Verzeichnis.This sample is located in the following directory.

<InstallDrive>:\WF_WCF_Samples\WCF\Basic\Client\UsingUsing

Siehe auchSee Also