tags:

views:

2112

answers:

4

hi all!

I have the following problem, basically i have a WCF service which operates fine in small tests. However when i attempt a batch/load test i get an InvalidOperationException with the message when the open() method is called on the proxy class:

"The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be modified while it is in the Opened state."

I have searched google, but cannot find anyone else really quoting this exception message.

I guess some further info on the service may be necessary for a diagnosis - when the service receives data through one of it's exposed methods, it basically performs some processing and routes the data to a service associated with the data (different data will result in different routing). To ensure that the service runs as quickly as possible, each cycle of receiving, processing and routing of the data is handled by a seperate thread in the threadpool. could this be a problem arising from one thread calling proxyClass.Open() whilst another is already using it? would a lock block eliminate this problem, if indeed this is the problem?

thanks guys, - ive been workikng on this project for too long, and finally want to see the back of it - but this appears to be the last stumbling block, so any help much appreciated :-)

=========================================================================

thanks for highlighting that i shouldn't be using the using construct for WCF proxy classes. However the MSDN article isn't the most clearly written piece of literature ever, so one quick question: should i be using a proxy as such:

try
{
    client = new proxy.DataConnectorServiceClient();
    client.Open();
    //do work
    client.Close();
 }
 .................. //catch more specific exceptions
 catch(Exception e)
 {
    client.Abort();
 }
A: 

It definitely sounds like you've called Open() multiple times on the same object.

Brian
+2  A: 

How are you using proxy? Creating new proxy object for each call. Add some code regarding how you use proxy.

Desired way of using proxy is for each call you create new proxy and dispose it once completed. You are calling proxy.open() for opened proxy that is wrong. It should be just called once.

Try using something like below in finally, as wcf does not dispose failed proxy and it piles up. Not sure it would help but give it a shot.

if (proxy.State == CommunicationState.Faulted)
{
    proxy.Abort();
}
else
{
    try
    {
     proxy.Close();
    }
    catch
    {
     proxy.Abort();
    }
}

Why to do this? http://msdn.microsoft.com/en-us/library/aa355056.aspx

Code you posted above would work but you will alway be eating exception. So handle wcf related exception in seperate catch and your generic catch with Excelion would abort then throw exception.

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw e;
}

Also if you still want to use convenience of using statement then you can override dispose method in your proxy and dispose with abort method in case of wcf error.

And do not need to call .Open() as it will open when required with first call.

mamu
im not misusing the proxy class. i call open() and close(), and instantiate a new object each time. the code follows the classic pattern:using(proxy = new proxy.DataConnectorServiceClient()){ try { proxy.open() //do work } finally { proxy.close(); }}hope that helps.
I think you'd better post your actual proxy handling code, unless that's it. "using (proxy =", not "using (var proxy ="? Is "proxy" shared between threads? If so, that's your problem. Otherwise post enough code to show what "proxy" is.
John Saunders
+1  A: 

I'm assuming you're using .NET 3.5 or later. In .NET 3.5, the WCF ClientBase'1 class (base class for generated client proxies) was updated to use cached ChannelFactories/Channels. Consequently, unless you're using one of the Client use/creation strategies which disables caching (Client constructor that takes in a Binding object, or accessing one of a few certain properties before the backing channel is created), even though you're creating a new Client instance, it could very well still be using the same channel. In other words, before calling .Open(), always ensure you're checking the .Created status.

Michael Smith
A: 

Hi, we hit the same roadblock as you sometime ago.

The issue with the using statement , is that if you get to a faulted state, it will still try to close at the end of the block. Another consideration, which was critical for us, is the cost of creating the proxy everytime.

We learned a lot from those blog posts:

http://blogs.msdn.com/wenlong/archive/2007/10/26/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared.aspx

and

http://blogs.msdn.com/wenlong/archive/2007/10/27/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.aspx

Hopefuly it will help you as well.

Cheers, Wagner.

Wagner Silveira