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.

Community
  • 1
  • 1
Jedidja
  • 16,610
  • 17
  • 73
  • 112
  • I doubt it's WCF - more likely, it's IIS and the ASP.NET app pools that block your communication. IIS hosting for WCF is a ..... suboptimal solution - I'd always host WCF services in my own NT Services or console apps. – marc_s Oct 09 '09 at 12:55
  • I'm a bit confused. Does your MVC app consume a WCF service which is hosted in another IIS instance? – d91-jal Oct 09 '09 at 12:57
  • marc_s Do you have any more information on why hosting WCF in IIS is suboptimal? We have to deploy this service at client's site and the easiest way to get them to agree seems to be hosting in IIS. – Jedidja Oct 09 '09 at 13:32
  • d91-jal Yes .. the MVC website consumes a WCF service which will be hosted on several remote (customer) sites. – Jedidja Oct 09 '09 at 13:33
  • well, the two main reasons: 1) it requires a bit more power, since IIS will create a new ServiceHost for each incoming request it needs to service (your self hosting app doesn't), and 2) if you host your WCF services in a IIS environment with other ASP.NET apps, you can be hit by side-effects of the ASP.NET app pools being recycled. It can be done more cleanly with separate app pools for WCF - but more often than not, it's not done. – marc_s Oct 09 '09 at 13:59

1 Answers1

2

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
  • 225,310
  • 48
  • 427
  • 736
  • 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 Oct 09 '09 at 13:35
  • 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 Oct 09 '09 at 13:40
  • 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 Oct 09 '09 at 16:12