2 out of 4 rated this helpful Rate this topic

Avoiding Problems with the Using Statement

This sample demonstrates how you should not use the C# "using" statement to automatically clean up resources when using a typed client. This sample is based on the Getting Started Sample that implements a calculator service. In this sample, the client is a console application (.exe) and the service is hosted by Internet Information Services (IIS).

Aa355056.note(en-us,VS.100).gifNote:
The setup procedure and build instructions for this sample are located at the end of this topic.

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.

The C# "using" statement results in a call to Dispose(). This is the same as Close(), which may throw exceptions when a network error occurs. 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. This represents a potential source of application errors.

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.");

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.

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.

Because the Dispose() occurs inside a "finally" block, the ApplicationException is never seen outside the using block if the Dispose() fails. If the code outside must know about when the ApplicationException occurs, the "using" construct may cause problems by masking this exception.

Finally, the sample demonstrates how to clean up correctly when exceptions occur in DemonstrateCleanupWithExceptions. This uses a try/catch block to report errors and call Abort. 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;
}
Aa355056.note(en-us,VS.100).gifNote:
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. 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.

When you run the sample, the operation responses and exceptions are displayed in the client console window.

The client process runs three scenarios, each of which attempts to call Divide. The first scenario demonstrates code being skipped because of an exception from Dispose(). The second scenario demonstrates an important exception being masked because of an exception from Dispose(). The third scenario demonstrates correct clean up.

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.

To set up, build, and run the sample

  1. Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. To build the C# or Visual Basic .NET edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Aa355056.Important(en-us,VS.100).gif Note:
The samples may already be installed on your machine. Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

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 WF samples. This sample is located in the following directory.

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

Did you find this helpful?
(2000 characters remaining)
Community Content Add
Annotations FAQ
WCF calls should be made asynchronously anyway

The using statement does not apply when making asynchronous WCF calls so maybe the WCF team was a little too smart for their own good by doing it this way. FYI - Silverlight does not even allow synchronous WCF calls, which I think was a brilliant idea; don't even let people write bad code! (that's what C++ is for)

Why is this not considered a bug?
Does anyone know why this is not considered a bug in the Entity Framework or in ADO.NET, or the .NET framework for that matter?  I wonder what Scott Guthrie or Vance Morrison would say about this.  It seems that the "Using" statement is failing its stated purpose. $0$0 $0 $0Thanks for any insight anyone can provide.$0 $0$0 $0 $0Matt$0
Woah, there, Brad!

.NET is flawed because you're not forced to deal with exceptions at every level of code?

If a Java app throw an exception and every level of code requires a "catch", then recursive code will rethrow an exception for every call level.  So if your code calls itself 100 times and then throws, the same exception will be rethrown 100 times.

Besides forcing developers to deal with exceptions at code abstraction levels that are inappropriate, it forces extra noise into your code.

Explanation
A good explanation and workaround can be found here: http://blogs.msdn.com/b/jjameson/archive/2010/03/18/avoiding-problems-with-the-using-statement-and-wcf-service-proxies.aspx

Design Flaw

This entire article would be unnecessary if WCF implemented dispose correctly. Dispose should not throw. Particularly egregious is Dispose throwing when the channel is simply in the Faulted state (throwing masks the original fault).

If WCF had followed FxCop, this problem would not exist. See:

http://msdn.microsoft.com/en-us/library/bb386039.aspx

.NET is flawed
One of the major flaws of .net is not forcing code to catch all thrown exceptions at compile time.  Java rules.
Why?
Can anyone explain why the Dispose method throws? Why does it need to use the network at all and why can't it handle the exception internally if it is so crucial that it needs to talk to the server when disposing?