views:

769

answers:

2

I have a WCF service hosted in IIS7 (the service and client configuration is at the end of this post). I have run across an odd scenario that I was hoping someone might have some ideas about how to attack it and find a solution.

The service only exposes one contract, 'ProcessMessage'. I can send/receive synchronous messages from the service using that contract just fine with expected performance, but one particular call to that contract returns more than 65KB of data; about 1 MB. Upon originally calling it, I received the expected max receive size exceeded error. So I increased the maxReceivedMessageSize, and now this particular call takes 40 minutes to return to the client. This is well beyond any of the timeout settings, and well beyond what I would expect it to take. The server side processing time is only 2 seconds. It appears to be held up on the client side.

I've also tried bumping up several of the other quotas in the file to no avail.

Any thoughts would be greatly appreciated. Thanks.

Service Config:

  <system.serviceModel>
<services>
  <service behaviorConfiguration="Lrs.Esf.Facade.Startup.FacadeBehavior"
    name="Lrs.Esf.Facade.Startup.FacadeService">
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="default" contract="Lrs.Esf.Facade.Startup.IFacadeService">
      <identity>
        <servicePrincipalName value="lrsdomain/PensionDev" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>
<bindings>
  <wsHttpBinding>
    <binding name="default">
      <security mode="None"/>
    </binding>
  </wsHttpBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior name="Lrs.Esf.Facade.Startup.FacadeBehavior">
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
      <serviceMetadata httpGetEnabled="true" />
      <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="true" />

    </behavior>
  </serviceBehaviors>
</behaviors>

Client Config:

  <system.serviceModel>
<bindings>
  <wsHttpBinding>
    <binding name="WSHttpBinding_IFacadeService" closeTimeout="00:01:00"
        openTimeout="00:01:00" receiveTimeout="00:1:00" sendTimeout="00:01:00"
        bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
        maxBufferPoolSize="52428800" maxReceivedMessageSize="6553600"
        messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
        allowCookies="false">
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
          maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
      <security mode="None">          
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
<client>
  <endpoint address="http://esf2.facade.testpe.pg.local/FacadeWcf/FacadeService.svc"
      binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IFacadeService"
      contract="FacadeServiceReference.IFacadeService" name="WSHttpBinding_IFacadeService">
    <identity>
      <servicePrincipalName value="lrsdomain/PensionDev" />
    </identity>
  </endpoint>
</client>

+1  A: 

You didn't increase the size of the various parameters on the server side, it seems - you should definitely try that! Use the binding configuration from your client config file on the server side as well - the service might well be choking since it's still defaulting to 64K message size.

Also, the receiveTimeout in your client binding is a bit funny - it's missing a zero digit:

<binding name="WSHttpBinding_IFacadeService" 
receiveTimeout="00:1:00"

You should use receiveTimeout="00:01:00"

Marc

marc_s
Thanks Marc. I didn't think those settings applied for the server side, but I tried that after your suggestion and it did not change the result. I also fixed the timeout.Since I received the original error regarding message size on the client side, my assumption is that the failure happened there and not on the server. The fact that the timeouts are not getting tripped is quite perplexing. It's almost like WCF finished processing the message on the client side and thinks it handed control back to the client, but is still blocking for some reason.
Mark
OK, interesting - and you're really not getting any timeouts or other errors on the client? That's rather odd......
marc_s
Do you see any entries in the event log of the server? Maybe IIS put something in the log? Seems odd there would be nothing at all....
marc_s
Just for the heck of it - could you write your own service host (a console app, which instantiates a ServiceHost and calls .Open() and it) and see if that works? You'll need to specify a base address or an explicit address for your endpoint on the server, too (in that scenario)
marc_s
No timeouts at all. I let it run for 15 minutes or so before killing it. No errors in the log either. The host app sounds like a decent thing to try. I'll give that a go. Thanks for your ideas Marc.
Mark
I updated the question as I found that it does return after 40 minutes! Still perplexed by this though.
Mark
A: 

I have figured out the basic cause of the issue and a work-around, however additional insight would be great.

The DataSet was getting serialized in XML format by WCF. I forced the DataSet to serialize as a byte[] and the time reduced to 4 seconds. One guess is that escaping all of the characters in 4MB of XML so that the HTTP communication was valid is what caused the problem.

Mark
Yet another reason to not use .NET-specific types in the contract of a service.
John Saunders
I have read that John. So what would you suggest when you need to transport a dataset across the wire. Serialize to JSON and deserialize on the other end?
Mark
I did a little further investigation and the dataset being returned contained one row and one column, but the value of that column was itself XML and quite large at that. I got around this by serializing the value of the column differently before WCF gets involved, and thus avoided this issue.
Mark