1

I am frustrated with this WCF fault handling problem. I've been researching it for 3 days now and don't seem to be any closer to a solution.

I found what I thought was the answer at How to heal faulted WCF channels? and at Disposing of WCF Clients but I've not been able to make it work in my environment. I'm using VB.NET 4.0 and trying to communicate with a vendors' server. They provided the wsdl and xsd files which svcutil turned into a proxy class that I have incorporated into my program.

Thus far, I have been successful in getting through the security stuff and in implementing 13 of the 14 endpoints. These seem to work fine. The one that doesn't work returns a State property of Created when the Client is instantiated:

Dim Client = New InquireBillingInvoiceDetailsPortTypeClient(ConfigName, AppEndPoint)
If Client.State = CommunicationState.Opened Then
    Client.Open()
    ' Code I'm not getting to
Else
    Client.Abort()
    Client = Nothing
End If

I understand that channels can fault but I don't understand why it is so difficult to clear the faulted condition after the fault condition has been corrected.

I am not getting anything in the traces either. There is no communication between the Client and the Server for this service like there is with the other endpoints. Shouldn't there be something in the svclog file related to this instantiation? This may be overkill but I'm including relevant portions of the app.config file here also. Any help would be greatly appreciated.

<basicHttpBinding>
   <binding name="InquireBillingInvoiceDetailsSoapHttpBinding"
     closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" 
     sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" 
     hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" 
     maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
     messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
     useDefaultWebProxy="true">
       <readerQuotas maxDepth="32" maxStringContentLength="8192" 
          maxArrayLength="16384" maxBytesPerRead="4096" 
          maxNameTableCharCount="16384" />
       <security mode="Transport">
          <transport clientCredentialType="Certificate" />
       </security>
   </binding>
</basicHttpBinding>

<client>
   <endpoint address="https://.../InquireBillingInvoiceDetails.jws"
      behaviorConfiguration="endPointCredentialBehavior" 
      binding="basicHttpBinding"
      bindingConfiguration="InquireBillingInvoiceDetailsSoapHttpBinding"
      contract="InquireBillingInvoiceDetailsPortType"
      name="InquireBillingInvoiceDetailsSoapHttpPort" />
</client>

<system.diagnostics>
   <sources>
      <source name="System.ServiceModel"
         switchValue="Information, ActivityTracing"
         propagateActivity="true">
         <listeners>
            <add name="xml" />
         </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging" 
         switchValue="All" >
         <listeners>
            <add name="xml" />
          </listeners>
      </sources>

      <sharedListeners>
         <add name="xml"
            type="System.Diagnostics.XmlWriterTraceListener"
            initializeData="U:\logs\Traces.svclog" />
      </sharedListeners>

      <trace autoflush="true" />
</system.diagnostics>
Community
  • 1
  • 1
Ebassador
  • 339
  • 3
  • 20
  • FYI … I’m not able to determine if you’re asking how to prevent the fault condition or how to recover from a faulted channel. – Seymour Jan 10 '14 at 22:37
  • I have no control over the server. I need to recover from the faulted channel condition. – Ebassador Jan 10 '14 at 22:42
  • Interesting, I wonder if you could subscribe to a channel event, perhaps "closed" or "faulted", and then take the necessary action to reset the connection. – Seymour Jan 10 '14 at 22:49
  • As this is my first project using WCF I am struggling to come up to speed with all the capability it provides. I'm not sure how to subscribe to a channel event as you suggest. That may well be all that is required but my research has led be to believe otherwise. Do you have any coding suggestions? – Ebassador Jan 10 '14 at 22:54
  • In a nutshell, once a channel (proxy) is in a faulted state, it cannot be used again. This [MSDN article explains](http://msdn.microsoft.com/en-us/library/aa355056.aspx) how to properly dispose of a faulted proxy. After doing this, you need to create a new instance of the service proxy to make another call. – Sixto Saez Jan 10 '14 at 23:38
  • First of all, I'm not using the _using_ construction referred to in that tutorial. Second, I _am_ disposing and recreating the instance of the service proxy (at least I think I am). I've stopped the client (debugging in VS 2010); even restarted the client machine with no change in results. The state of the InquireBillingInvoiceDetailsSoapHttpPort client is persistent. What am I missing? – Ebassador Jan 10 '14 at 23:46
  • 2
    I see you got an answer from Tim that may work for you. I would take a different approach. The WCF `ClientBase` class has built-in `ChannelFactory` caching (similar to `SqlConnection` connection pools). Take advantage of this by making service calls inside a `try/catch` where you instantiate a new `InquireBillingInvoiceDetailsPortTypeClient` for each service call & in the `catch` do the `Client.Abort()`. Might seem inefficient but it performs well and is a failsafe of managing `ClientBase` inherited objects. See [this article.](http://msdn.microsoft.com/en-us/library/hh314046(v=vs.110).aspx) – Sixto Saez Jan 11 '14 at 16:18
  • Approach by @SixtoSaez in the comment above seems more viable. It's good to handle when faulted rather then if else check in every case. I have done that way too. – Pranav Singh Jan 14 '14 at 11:31
  • @sixto @ pranav I believe the code you are referring to is generated proxy code from svcutil. Are you recommending the try/catch be added there? – Ebassador Jan 14 '14 at 15:18
  • Not in the actual generated code from SvcUtil (or Add Service Reference) but in the application code that instantiates the proxy. Unlike any other .NET framework `IDisposible` class that I'm aware of, WCF allows exceptions to occur (and be thrown) in the `Dispose()` method of `ClientBase`. Microsoft says this is **by design** so you gotta live with it. This design spawned a "religious war" some years ago, you can google it for more info. The up-shot is that a try/catch is essential to *proper* disposal of the `ClientBase` proxy. – Sixto Saez Jan 14 '14 at 16:53

2 Answers2

1

CommunicationState.Created is not a fault. It simply "Indicates that the communication object has been instantiated and is configurable, but not yet open or ready for use."

In the code snippet you provided, you're checking to see if the CommunicationState is Opening (which "Indicates that the communication object is being transitioned from the Created state to the Opened state. "), but you haven't issued the Open() command yet, so its still at the Created state. This is why your code doesn't reach the Client.Open() statement.

Try something like this:

Dim Client = New InquireBillingInvoiceDetailsPortTypeClient(ConfigName, AppEndPoint)

If Client.State = CommunicationState.Created Then
    Client.Open()
Else
    Client.Abort()
    Client = Nothing
End If

There are 6 states (details here - CommunicationState Enumeration) - Closed, Closing, Created, Faulted, Opening, Open.

Tim
  • 28,212
  • 8
  • 63
  • 76
0

The finished code looks like this:

Dim Client = New InquireBillingInvoiceDetailsPortTypeClient(ConfigName, AppEndPoint)

Client.Open()
If Client.State = CommunicationState.Opened Then
    ' useful code
Else
    Client.Abort()
    Client = Nothing
End If
Ebassador
  • 339
  • 3
  • 20