If you're trying to be a conscientious developer and making sure that you cleanup your resources - great! You are writing 'using()' blocks around all of your disposable items - great...except when the disposable item is a WCF Client/Proxy!
The using() statement and the try/finally effectively have the same IL:
// The IL for this block is effectively the same as
// the IL for the second block below
using (var win = new Form())
{
}
// This is the second block
Form f = null;
try
{
f = new Form();
}
finally
{
if (f != null)
{
f.Dispose();
}
}
Here's the IL for the 'using()' block above compiled in Release mode:
IL_0000: newobj instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
IL_0005: stloc.0
.try
{
IL_0006: leave.s IL_0012
} // end .try
finally
{
IL_0008: ldloc.0
IL_0009: brfalse.s IL_0011
IL_000b: ldloc.0
IL_000c: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0011: endfinally
} // end handler
Here's the IL for the second block (try/finally) compiled in Release mode:
IL_0012: ldnull
IL_0013: stloc.1
.try
{
IL_0014: newobj instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
IL_0019: stloc.1
IL_001a: leave.s IL_0026
} // end .try
finally
{
IL_001c: ldloc.1
IL_001d: brfalse.s IL_0025
IL_001f: ldloc.1
IL_0020: callvirt instance void [System]System.ComponentModel.Component::Dispose()
IL_0025: endfinally
} // end handler
As you can see, the IL is nearly identical.
Well this is all fine and good but let's get back to the issue with WCF. The problem is that if an exception is thrown during disposal of the WCF client/proxy, the channel is never closed. Now, in general, any exception that occurs during disposal of an object is indeed undesirable. But, in the case of WCF, multiple channels remaining open could easily cause your entire service to fall on its face - not to mention what might eventually happen to your web server.
Here is an alternative solution that can be used:
WCFProxy variableName = null;
try
{
variableName = new WCFProxy();
// TODO code here
variableName.Close();
}
// if you need to catch other exceptions, do so here...
catch (Exception)
{
if (variableName != null)
{
variableName.Abort();
}
throw;
}
try
{
variableName = new WCFProxy();
// TODO code here
variableName.Close();
}
// if you need to catch other exceptions, do so here...
catch (Exception)
{
if (variableName != null)
{
variableName.Abort();
}
throw;
}
MSDN does have a brief on this issue which you can read here - http://msdn.microsoft.com/en-us/library/aa355056.aspx
No comments:
Post a Comment