Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting WCF callbacks to work with the netTcpBinding

I am having some issues getting callbacks working with my netTcpBinding WCF client/server. Here is the code... any thoughts?

Service Side

contract:

using System.Runtime.Serialization;
using System.ServiceModel;

namespace API.Interface
{
   [ServiceContract(CallbackContract = typeof(IServiceCallback))]
   public interface IMyService
   {
       [OperationContract]
       void DoSomething();
   }

   public interface IServiceCallback
   {
        [OperationContract(IsOneWay = true)]
        void OnCallback();
   }
}

service:

using System;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Timers;
using API.Interface;

namespace API.Service
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
    public class MyService : IMyService
    {
        public static IServiceCallback callback;
        public static Timer Timer;

        public void DoSomething()
        {
            Console.WriteLine("> Session opened at {0}", DateTime.Now);
            callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();

            Timer = new Timer(1000);
            Timer.Elapsed += OnTimerElapsed;
            Timer.Enabled = true;

        }

        void OnTimerElapsed(object sender, ElapsedEventArgs e)
        {
            callback.OnCallback();
        }
    }
}

Here is the code that I am using to start the service

        var service = new MyService();
        // Start up the WCF API
        var service = new ServiceHost(turboService);
        service.Open();

Here is the App.Config

   <system.serviceModel>
    <services>
      <service name="API.Service.MyService">
        <endpoint address="" binding="netTcpBinding" bindingConfiguration=""
          contract="API.Interface.IMyService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
          contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8732/MyService/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="">
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Client Side

CallbackService

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using USBAutomationTester.ServiceReference;

namespace USBAutomationTester
{
    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
    public class CallbackService : IMyServiceCallback
    {
        public void OnCallback()
        {
            Console.WriteLine("> Received callback at {0}", DateTime.Now);
        }
    }
}

Connecting and calling

 var instanceContext = new InstanceContext(new CallbackService());
 var service = new TurboValidateServiceClient(instanceContext);
 service.DoSomething();

App.Config

  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="NetTcpBinding_IMyService" />
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="net.tcp://localhost:8732/MyService/"
        binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ITurboValidateService"
        contract="ServiceReference.IMyService"
        name="NetTcpBinding_IMyService">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>

I believe I have all the pieces needed. Google searching has led me down several different paths with no real result. I can see the service calling the callback, but my client is never getting it.

Thanks in advance, I know this is a WCF 101 type question, but I am stumped at this point.

UPDATE

On the client, I am getting this exception

"The incoming message with action could not be processed because it is targeted at a request-reply operation, but cannot be replied to as the MessageId property is not set."

followed by

"The channel received an unexpected input message with Action 'http://tempuri.org/IMyService/OnCallback' while closing. You should only close your channel when you are not expecting any more input messages."

like image 267
AndySousa Avatar asked Nov 07 '13 18:11

AndySousa


1 Answers

It may be the problem is that the context is already closed by the time your timer fires.

    public void DoSomething()
    {
        Console.WriteLine("> Session opened at {0}", DateTime.Now);
        callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();

        Timer = new Timer(1000);
        Timer.Elapsed += OnTimerElapsed;
        Timer.Enabled = true;

    }

    void OnTimerElapsed(object sender, ElapsedEventArgs e)
    {
        callback.OnCallback();
    }

Try casting your callback to ICommunicationObject and checking the State property. If it isn't set to Open when you're attempting OnCallback, that's your problem.

like image 163
SouthShoreAK Avatar answered Oct 04 '22 03:10

SouthShoreAK