views:

290

answers:

1

This is my first attempt to use WCF so there may be something fundamentally wrong with this approach - if so I'm happy to switch to a different model. At quick glance, I thought the answer to this question would have worked, but my scenario appears to be different.

I have an ASP.NET MVC website where the controllers access the WCF client class through an intermediate repository. The repository is just a wrapper around the WCF client that instantiates it once and sets the proper endpoint address.

public class WcfRepository : IRepository
{
    private MyWCFServiceClient client;

    public WcfRepository()
    {
        client = new MyWCFServiceClient();
    }

    public bool MyMethod1()
    {
         return client.MyMethod1();
    }

    ... etc       
}

I can access different pages on the website until a seemingly random point where the WCF service will start timing out. It doesn't matter which method I call either - it timesout on different ones. I cannot see any exceptions on the IIS machine hosting the WCF service either; the event log there is empty. A simple method like GetCustomerByName() which worked two minutes earlier will no longer so I think it's more to do with WCF communication rather than the service itself.

If I try to use the WCF Test Client after one of these timeouts occurs, it will also fail. But, if I wait a while (and choose 'start a new proxy') then things will work again.

I'm very confused - should I be creating a new instance of the WCF client each time I want to use it in my repository? Is there another way I should be using the client? Wrapping each call in Open()/Close() doesn't work either since the first call to Close() puts the object in a disposed state.

+2  A: 

When you are done with your WCF client, you must explicitly close it because it will otherwise keep a 'connection' open to the service, and there's a (configurable) limit to how many concurrent connection you can have.

Although it is possible to tweak that limit, the correct solution is to create a new WCF client, invoke one or more methods on it and close it again when you are done. This is considered best practice, and should neatly avoid the sort of problems you are currently experiencing.

This means that your implementation should rather go something like this:

public class WcfRepository : IRepository
{
    public bool MyMethod1()
    {
         var client = new MyWCFServiceClient();
         try
         {
             return client.MyMethod1();
         }
         finally
         {
             try
             {
                 client.Close();
             }
             catch(CommunicationException)
             {
                 // handle exception here
             }
             catch(TimeoutException)
             {
                 // handle exception here
             }

         }
    }

    ... etc       
}

Notice the nasty try/finally construct, which is necessary because Close may throw. Read more about this here.

Mark Seemann
Mark - can you recommend any good reading materials on the subject? Also, are there any best practices when it comes to wrapping this try/finally/try in some sort of generic manner? Seems like a lot of boilerplate code that could possibly be simplified.
Jedidja
This link can be handy: http://www.slideshare.net/blowdart/10-tricks-and-tips-for-wcf .. Slide 15 shows a similar method of disposing.
Jedidja
Last time I had to deal with this, I wrote a reusable method that did all this boilerplate code and took a Func as input parameter so that I could just pass the Func to the method and have safe handling of the client.
Mark Seemann