views:

89

answers:

3

I'm trying to find out if it is neccessary to close a .net service reference client when you are done using it. Almost all of the examples that I have come across on the net don't seem to, but the client that is generated implements IDisposable and since it does open a connection to a service, my intuition tells me you need to close that connection when you are done with it.

Here is a code sample I pulled from http://msdn.microsoft.com/en-us/library/bb386386(v=VS.90).aspx :

private void button1_Click(System.Object sender, System.EventArgs e)
{
    ServiceReference1.Service1Client client = new 
        ServiceReference1.Service1Client();
    string returnString;

    returnString = client.GetData(textBox1.Text);
    label1.Text = returnString;
}

I would think that you should at least call client.Close() at the end of this method, and better yet wrap the first line in a using statement. I just wanted to get some feedback on this to find out what the best practices are.

+3  A: 

Best practice is, if the class implements IDisposable, call Dispose() in a finally clause, or wrap it with using () { }

Edit
Following the @casperOne comment below, it seems WCF clients should be treated more cautiously. I didn't know that, and am a little unsettled by it, with using() having served me well thus far.

Neil Moss
I'm confused why all the msdn examples I found don't do this. Wouldn't they want to illustrate best practices in the examples they give?
Criss
You'd hope so, but I reckon the samples are generally demonstrating specific points about other classes. I've seen Crypto samples which encode a file that don't even try/catch around FileStream instances, and we'd never do that, would we? (!)
Neil Moss
-1: Things that implement ICommunicationObject cannot simply have Dispose called on them, for reasons pointed out here: http://caspershouse.com/post/Using-IDisposable-on-WCF-Proxies-(or-any-ICommunicationObject-implementation).aspx and here: http://msdn.microsoft.com/en-us/library/aa355056.aspx - You have to Abort in the face of certain exceptions and *then* call Dispose.
casperOne
Live and learn - thanks @casperOne. Will modify accordingly.
Neil Moss
+1: This ought to be seen as a bug in the ICommunicationObject implementation. Since when did we start putting up with unexpected using statement results?
slf
@slf: we've put up with it since 2006, when WCF shipped. It's a design flaw, not a bug.
John Saunders
design flaws are bugs
slf
A: 

The best thing to do is look at the generated client code for Dispose() and see if it's really disposing of anything, like HTTP connections or something.

On one hand, it may just be that the interface it implements inherits from IDisposable because some client might need to dispose of something, even though that particular one doesn't. That's similar to MemoryStream, a class that implements IDisposable because all Streams do, but that doesn't actually deal with any unmanaged resources.

On the other hand, it never hurts to use using, even if Dispose() is an empty method. And MS examples are actually really bad about not using using even if they should (e.g. here), so don't take their example as good evidence that you don't need to.

Isaac Cambron
I'd personally rather not reverse engineer 3rd party assemblies to see if I can get away with not calling Dispose - doesn't this introduce risks that, come the next version of the component or framework, you *need* to dispose and are left with a codebase that leaves unmanaged resource cleanup to the GC?
Neil Moss
-1: Coding against implementation and not by contract is *always* a bad idea. If the type implements IDisposable, then Dispose should *always* be called. The only reasons not to are when it is determined that you have a special case and it is harming your system in doing so and need a workaround. Also, in your example of MemoryStream, you *should* call Dispose, because it is not guaranteed that unmanaged memory won't be used in the future as a backing store, so your code won't be future proof if that aspect is changed.
casperOne
@neil, then by all means call Dispose(); I suggested it because you have the actual code. @casperOne, coding to the interface is very often a good idea, but as an inflexible rule, it loses sight of the fact that type systems aren't perfect. The unmanaged memory piece, for example, is red herring: I can implement IList to use unmanaged memory, but if the consumer codes to the IList interface, he won't even know he can call Dispose().
Isaac Cambron
er, I mean the OP has the actual code
Isaac Cambron
-1: _never_ reverse-engineer something as complicated as WCF and then depend on it. Especially, since the generated client code is not what's doing the actual work - it's the base class, which is part of WCF.
John Saunders
You're suggesting that reading the code you generated is reverse-engineering all of WCF? Not so much. Also, the italicized usage of the already very strong "always" and "never" grossly overstate your cases. The OP asked if he needs to call Close on his object, and the answer is--no matter how many engineering maxims you pull out--that it depends on what the code says.
Isaac Cambron
@Issac Cambron: Your argument is flawed. If the concrete class that you were using implemented IDisposable (or IList derived from IDisposable) then it's part of the contract and my original point applies. If you were using something like unmanaged memory and *didn't* have the implementing type implement IDisposable, then that is a design/implementation bug, and renders your point moot.
casperOne
Of course it would implement IDisposable, but you wouldn't know that unless you knew the underlying type, or did a runtime check, i.e. the IList interface doesn't have enough information on its own. The point is that is often helpful to know what the object you have actually is and does. Coding to the interface is a useful design principle, but not the sort of thing to attach "*always*" to. In this example, the coder actually generated the code with a tool - if he wants to know how it behaves, he should just look.
Isaac Cambron
+5  A: 

Yes, you do, but you need to be very careful when doing so. While closing anything that implements ICommunicationObject the potential exists to cause the disposal of the object to take an excessive amount of time in the event that there is an error or fault on the channel.

Because of this, it is prescribed that you call the Close method and then call the Dispose method on IDisposable, using a number of catches for certain exception types and calling Abort before you finally call Dispose.

You can wrap this logic up into an IDisposable implementation which you can use in a using statement, as I've outlined in a blog post on this matter.

The key here is to create a token that implements IDisposable and then in that implementation, call Close, catch the relevant exceptions, call Abort (if necessary) and then call Dispose.

This is implemented as an extension method which returns an IDisposable on it which in turn allows you to use it in a using statement.

casperOne
+1: I did not know that, and now I do.
Neil Moss
Thanks, that is the exact kind of explaination I was looking for.
Criss