views:

678

answers:

3

Ive got a Host / Client WCF Service and client that is using netTcpBinding and a callback method.

<bindings>
      <netTcpBinding>
        <binding name="tcp_Unsecured" receiveTimeout="00:01:00" sendTimeout="00:01:00">
          <security mode="None" />
          <reliableSession enabled="true" ordered="true" inactivityTimeout="00:10:00"/>
        </binding>
      </netTcpBinding>
</bindings>

Proxy

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples", ConfigurationName="AlarmServer", CallbackContract=typeof(AlarmServerCallback), SessionMode=System.ServiceModel.SessionMode.Required)]
public interface AlarmServer
{

    [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/RegisterAlarm")]
    void RegisterAlarm(System.DateTime alarmTime, string clientName, string reminderMessage);

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/unRegisterAlarm")]
    void unRegisterAlarm(string clientName);

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/broadcastMessage")]
    void broadcastMessage(string msg);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface AlarmServerCallback
{

    [System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/SignalAlarm")]
    void SignalAlarm(string reminderMessage);

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "http://dotnetaddict.dotnetdevelopersjournal.com/wcf.samples/AlarmServer/displayMessage")]
    void displayMessage(string msg);
}

client instance with callback public MainForm() { InitializeComponent(); InstanceContext context = new InstanceContext(new AlarmCallback()); client = new AlarmServerClient(context);

        }

The problem I have is that after the binding recieveTimeout triggers, the client goes into a faulted state and closes the clients listening callback.

I can see the listening port drop using TCPVIEW from sysinternals.

If I keep the channel busy, the time out does not trigger, so its not a fault in the WCF message to the Server/Client, as multiple messages will flow through ok.

I thought the receiveTimeout was designed to provide a way to detect if a reply from the WCF message over TCP failed? Why is it faulting the connection. It almost appears that if there are no callback object created for the timeout period, the channel is then closed?

What am I doing wrong?

+1  A: 

Have you tried using a DuplexChannelFactory, in the proxy creation (client)? Here's how it's used (replace the creation using new AlarmServerClient(context)):

AlarmServer proxy = new DuplexChannelFactory<AlarmServer>(context,"YourAlarmServerEndpoint").CreateChannel();

EDIT: Enabling log to analyse trace:

Its possible to analyse the channels communication, by enabling Message logging and Trace:

<system.diagnostics>
<sources>
  <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
    <listeners>
      <add type="System.Diagnostics.DefaultTraceListener" name="Default">
        <filter type="" />
      </add>
      <add name="ServiceModelMessageLoggingListener">
        <filter type="" />
      </add>
    </listeners>
  </source>
  <source name="System.ServiceModel" switchValue="Information,ActivityTracing"
    propagateActivity="true">
    <listeners>
      <add type="System.Diagnostics.DefaultTraceListener" name="Default">
        <filter type="" />
      </add>
      <add name="ServiceModelTraceListener">
        <filter type="" />
      </add>
    </listeners>
  </source>
</sources>
<sharedListeners>
  <add initializeData="Your_svclog_file_here"
    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
    <filter type="" />
  </add>
  <add initializeData="Your_svclog_file_here"
    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
    name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
    <filter type="" />
  </add>
</sharedListeners>
<trace autoflush="true" />

In this case, the Trace is able to log "Information". Its important to see the channels creation.

To analyse the svclog file, you can use the Service Trace Viewer - Microsoft Windows SDK, usually in C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe

Erup
Tried it, didnt seem to help.Im still baffelled!!
PrimeTSS
Ive also simplified the bindings and got rid of the time outs and reliablesession properties <binding name="tcp_Unsecured" > <security mode="None" /> </binding> Still the call back channel goes into a "Fault" state (love to know why and get more info on this fault?)
PrimeTSS
By enabling log, you can analyse where the communication is crashing. Hope it helps!
Erup
Thanks Enabled Tracing and this is what I get A TCP error (995: The I/O operation has been aborted because of either a thread exit or an application request) occurred while transmitting data.
PrimeTSS
Try changing the NetTcpBinding to WsDualHttpBinding and removing (temporary) the reliableSession binding element.
Erup
Thanks for the TraceListner tip that was helpfull
PrimeTSS
A: 

Seems the Receivetime out causes the callback host service to fault after it reaches its max count. Which is 23.59 hrs or the default of 1 minute. I can resolved the timeout issue with setting receivetimeout to Infinate

 <bindings>
      <netTcpBinding>
        <binding name="NetTcpBinding_AlarmServer" receiveTimeout="infinite" >
          <security mode="None" />        
        </binding>
      </netTcpBinding>
    </bindings>

But this has me now wondering if im really using the right tool in WFC for Server/Client communications. I want a Host/Server to be running on a file server, and multiple remote clients connected to it. The client will ping the server with a heartbeat, and occasionally the server might send a command to the client. I was doing this with remoting or tcpsockets and using a "client polling method", where commands where quued in a database and when the client polled the server for a command every 10 mins, if there was a pending command for that unique client it got it. This worked ok, and had the advantage of NOT having 1000 open tcp socket connections to the server, as client would only randomly connect and disconnect. BUT I decided to try WCF (after all isnt this the new latest in greates replacing Remoting?) and when I found Duplex I thought, Id use it.... NOW Im thinking Im missing the point about what WCF Duplux is for ???

Help am I missing the concepts here???

PrimeTSS
A: 

The value at which the receiveTimeout is set will tell the service how long to wait before faulting the communication channel when no application message is received. You can always increase this timeout value to a greater number (default is 10 minutes), but you then also have to increase the session inactivity timeout. Please see http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding.receivetimeout.aspx for more information on both of these timeouts.

When the receive or inactivity timeout fires, the duplex channel is faulted. You will have to create a new proxy on the client side to be able to communicate with the server again.

You can always check the channel connection status on the client side before trying to call the server. If the CommunicationState of the channel is not opened, then you can create a new proxy before calling the server.

jean-ian