user481779
user481779

Reputation: 1081

WCF asynchronous callback

I have successfully implemented the WCF callback pattern in my code and now I want to implement an asynchronous callback. Here is my interface code:

[ServiceContract(Name = "IMessageCallback")]
public interface IMessageCallback
{
  [OperationContract(IsOneWay = true)]
  void OnMessageAdded(string message, DateTime timestamp);
}

[ServiceContract(Name="IMessageCallback")]
public interface IAsyncMessageCallback
{
  [OperationContract(AsyncPattern = true)]
  IAsyncResult BeginOnMessageAdded(string msg, DateTime timestamp, AsyncCallback callback, object asyncState);
  void EndOnMessageAdded(IAsyncResult result);
}

[ServiceContract(CallbackContract = typeof(IMessageCallback))]
public interface IMessage
{
  [OperationContract]
  void AddMessage(string message);
}

To use the synchronous callback I declared my channel and endpoint like so:

DuplexChannelFactory<IMessage> dcf = new DuplexChannelFactory<IMessage>(new InstanceContext(this), "WSDualHttpBinding_IMessage");
<endpoint address="net.tcp://localhost:8731/Message/"
            binding="netTcpBinding"
            contract="WCFCallbacks.IMessage" name="WSDualHttpBinding_IMessage">

I am having trouble getting the right combination of endpoint and channel to utilize the asynchronous callback. Can someone point me in the right direction?

In addition when the following line of code is executed:

OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>();

I get the following error:

Unable to cast transparent proxy to type 'WCFCallbacks.IAsyncMessageCallback'

Upvotes: 7

Views: 17873

Answers (1)

carlosfigueira
carlosfigueira

Reputation: 87218

You need to change the CallbackContract property of the service contract IMessage to that type (IAsyncMessageCallback). The example below runs with the async callback.

    public class StackOverflow_5979252
{
    [ServiceContract(Name = "IMessageCallback")]
    public interface IAsyncMessageCallback
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginOnMessageAdded(string msg, DateTime timestamp, AsyncCallback callback, object asyncState);
        void EndOnMessageAdded(IAsyncResult result);
    }
    [ServiceContract(CallbackContract = typeof(IAsyncMessageCallback))]
    public interface IMessage
    {
        [OperationContract]
        void AddMessage(string message);
    }
    [ServiceBehavior(IncludeExceptionDetailInFaults = true, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class Service : IMessage
    {
        public void AddMessage(string message)
        {
            IAsyncMessageCallback callback = OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>();
            callback.BeginOnMessageAdded(message, DateTime.Now, delegate(IAsyncResult ar)
            {
                callback.EndOnMessageAdded(ar);
            }, null);
        }
    }
    class MyClientCallback : IAsyncMessageCallback
    {
        public IAsyncResult BeginOnMessageAdded(string msg, DateTime timestamp, AsyncCallback callback, object asyncState)
        {
            Action<string, DateTime> act = (txt, time) => { Console.WriteLine("[{0}] {1}", time, txt); };
            return act.BeginInvoke(msg, timestamp, callback, asyncState);
        }

        public void EndOnMessageAdded(IAsyncResult result)
        {
            Action<string,DateTime> act = (Action<string,DateTime>)((System.Runtime.Remoting.Messaging.AsyncResult)result).AsyncDelegate;
            act.EndInvoke(result);
        }
    }
    static Binding GetBinding()
    {
        return new NetTcpBinding(SecurityMode.None);
    }
    public static void Test()
    {
        string baseAddress = "net.tcp://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.AddServiceEndpoint(typeof(IMessage), GetBinding(), "");
        host.Open();
        Console.WriteLine("Host opened");

        InstanceContext instanceContext = new InstanceContext(new MyClientCallback());
        DuplexChannelFactory<IMessage> factory = new DuplexChannelFactory<IMessage>(instanceContext, GetBinding(), new EndpointAddress(baseAddress));
        IMessage proxy = factory.CreateChannel();
        proxy.AddMessage("Hello world");

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        ((IClientChannel)proxy).Close();
        factory.Close();
        host.Close();
    }
}

Upvotes: 11

Related Questions