tags:

views:

395

answers:

6

In our project we are making WCF calls using the following Code.

// In generated Proxy we have..
public static ICustomer Customer
{
 get
  {
    ChannelFactory<ICustomer> factory = new ChannelFactory<ICustomer>("Customer");
    factory.Endpoint.Behaviors.Add((System.ServiceModel.Description.IEndpointBehavior)new ClientMessageInjector());
    ICustomer channel = factory.CreateChannel();
    return channel;
  }
}

and we have Service Proxy class which has the methods like

public static Datatable GetCustomerDetails(int id)
{
  return Services.Customer.GetCustomerDetails(id);
} 

public static void .SaveCustomerDetails (int id)
{
  Services.Customer.SaveCustomerDetails(id) ;
}

etc... which we use to make business calls.

Recently we found out that we need to "Close" the wcf connection and we are trying to find out away to do this without asking our developers to change too much of their code.

Please provide us with some suggestions which would help us achieve this goal

A: 

The right way to close connections is to put the client in a using block, or put the close in a finally. Otherwise, they will only get closed if no exception is thrown.

Steven Sudit
Not in the case of a WCF client! Since there's a good chance of an exception when the .Close() method is called, just putting it in a using() block is **not** the recommended best practice.
marc_s
That's true. The usual solution is to wrap it in an object that implements IDisposable and has a try/catch in the Dispose. This way, you can safely use using. I'd post code but I know it's appeared in other questions. Without this, you'd have to use a try/catch in the finally, which works but is awkward.
Steven Sudit
watch out for gobbled exceptions if the Close in the Finally Block of the using throwshttp://msdn.microsoft.com/en-us/library/ms733912(printer).aspx
BozoJoe
+2  A: 

The accepted "best practice" for this case would be someting along the lines of this:

// create your client
ICustomer channel = CreateCustomerClient();

try
{
   // use it
   channel.GetCustomerDetails() ....

   (more calls)

   // close it
   channel.Close();
}
catch(CommunicationException commEx)
{
   // a CommunicationException probably indicates something went wrong 
   // when closing the channel --> abort it
   channel.Abort();
}

Typically, since the channel also implements "IDisposable", you might be tempted to just simply put it in a

using(ICustomer channel = CreateCustomerChannel()) 
{
   // use it
}

block - unfortunately, that could bomb out since there's a good chance that when attempting to call .Close() on your channel, you'll get another exception (which would go unhandled in this case).

Our moderator here, Marc Gravell, has an interesting blog post (don't(don't(use using)) on the topic, with an elegant solution to the problem.

Marc

marc_s
+1  A: 

The information in this question may also be helpful.

Eric King
A: 

Unfortunately we use the generated Proxy methods which returns the channel and we use it in many places.So i was thinking there would be some way to "extend" the channel and close the connection after making the call(using extension methods).

developer
Please edit your question instead of adding an answer. If you've lost access to the original account, then click the "contact us" link at the bottom of the page to ask the accounts be merged.
John Saunders
A: 

You are also leaking ChannelFactory<T> objects in the current approach. You should close these, too. If you use the static CreateChannel methods on ChannelFactory<T>, you will get auto-close behavior for the factory when the client closes so that could help solve that problem. Unfortunately, the static CreateChannel(string endpointConfigurationName) overload is protected, so you'd need to subclass ChannelFactory<T> in order to call it. (This might not be so bad overall.)

Now, if you want "auto-close" behavior of a channel and you are using a sessionful contract (SessionMode = SessionMode.Required), you can mark all your service operations "IsInitiating = true, IsTerminating = true" in the [OperationContract] attribute. Note that this will prevent you from ever being able to call more than one operation using the same ICustomer proxy. This might be the easiest option, if it is available to you.

As for your general approach, it is not considered good design for a property to do too much work, especially when it involves constructing new (expensive) objects and hitting the network. WCF proxies are nice abstractions and look like simple interface implementations, but they are not stateless and must be managed appropriately.

bobbymcr
A: 

Do not create a new channel factory each time you create a channel. This is horrible from a performance point of view!

Alex