44

I am trying to learn WCF. I have a simple client and server application setup and upon pressing a button on the client, it gets an updated value from the server.

My next step is I am trying to do a callback from the server to the client to update its value. I have poured through many examples, and they just seem too big and confusing. Is there anyone that can give my just the simplest example of its implementation in C#?

I keep looking through examples online and I just do not understand what it takes? Of course I could copy the example line by line but that does me no good because I still don't what to implement if I wanted to do this in my own code.

Could someone please help me with a very simple example on what steps I would need to take and what I would need to do in the server code and then in the client code to make this happen?

Thank you

kevin bailey
  • 483
  • 2
  • 6
  • 6

4 Answers4

87

Here is about the simplest complete example that I can come up with:

public interface IMyContractCallback
{
    [OperationContract]
    void OnCallback();
}

[ServiceContract(CallbackContract = typeof(IMyContractCallback))]
public interface IMyContract
{
    [OperationContract]
    void DoSomething();
}

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MyService : IMyContract
{
    public void DoSomething()
    {
        Console.WriteLine("Hi from server!");
        var callback = OperationContext.Current.GetCallbackChannel<IMyContractCallback>();
        callback.OnCallback();
    }
}

public class MyContractClient : DuplexClientBase<IMyContract>
{
    public MyContractClient(object callbackInstance, Binding binding, EndpointAddress remoteAddress)
        : base(callbackInstance, binding, remoteAddress) { }
}

public class MyCallbackClient : IMyContractCallback
{
    public void OnCallback()
    {
        Console.WriteLine("Hi from client!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var uri = new Uri("net.tcp://localhost");
        var binding = new NetTcpBinding();
        var host = new ServiceHost(typeof(MyService), uri);
        host.AddServiceEndpoint(typeof(IMyContract), binding, "");
        host.Open();

        var callback = new MyCallbackClient();
        var client = new MyContractClient(callback, binding, new EndpointAddress(uri));
        var proxy = client.ChannelFactory.CreateChannel();
        proxy.DoSomething();
        // Printed in console:
        //  Hi from server!
        //  Hi from client!

        client.Close();
        host.Close();
    }
}

A few namespaces will need to be included in order to run the example:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
Ray Vernagus
  • 6,130
  • 1
  • 24
  • 19
  • 1
    I still think it's too hard. Im going to implement by socket :P – alansiqueira27 Sep 16 '12 at 23:39
  • 5
    Copy/pasting this solution didn't work for me (VS2010, .NET 4.0). The client and will block waiting for the server to respond and you'll get timeout exceptions. You have to put [OperationContract(IsOneWay=true)] on DoSomething. Alternatively, you can either handle the threading yourself or set ConcurrencyMode=Multiple, UseSynchronizationContext=false on MyCallbackClient. See this question/answer: http://stackoverflow.com/a/13091230/2184185 – Walter Wilfinger Jul 03 '13 at 19:30
  • This is the single most helpful thing I have found trying to learn duplex communication in WCF. – вʀaᴎᴅᴏƞ вєнᴎєƞ Feb 09 '15 at 23:41
  • I was wondering why ConcurrencyMode.Reentrant was added. Without it one would get an exception on the service side that goes: "An exception of type 'System.InvalidOperationException' occurred in mscorlib.dll but was not handled in user code Additional information: This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on ServiceBehaviorAttribute." – Lzh Jan 16 '17 at 19:47
3

Grab a copy of "Programming WCF Services, 2nd Edition" by Juval Lowy. There are large sections of the book devoted to Callback operations. In Chapter 5, start on page 214. In the chapter on Concurrency Management (ch. 8) there's even more information.

"Programming WCF Services" is more or less the WCF "bible."

Tad Donaghe
  • 6,625
  • 1
  • 29
  • 64
3

I know, old question... I came across this question from a google search earlier today and the answer provided by Ray Vernagus is the easiest to understand example of WCF that I have read to date. So much so that I was able to rewrite it in VB.NET without using any online converters. I thought I'd add the VB.NET variant of the example that Ray Vernagus provided. Just create a new VB.NET Windows Console application, add a reference to System.ServiceModel, and copy/paste the entire code below into the default Module1 class file.

Imports System.ServiceModel
Imports System.ServiceModel.Channels



Public Interface IMyContractCallback
    <OperationContract()> _
    Sub OnCallBack()
End Interface

<ServiceContract(CallBackContract:=GetType(IMyContractCallback))> _
Public Interface IMyContract
    <OperationContract()> _
    Sub DoSomething()
End Interface

<ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Reentrant)> _
Public Class Myservice
    Implements IMyContract

    Public Sub DoSomething() Implements IMyContract.DoSomething
        Console.WriteLine("Hi from server!")
        Dim callback As IMyContractCallback = OperationContext.Current.GetCallbackChannel(Of IMyContractCallback)()
        callback.OnCallBack()
    End Sub
End Class

Public Class MyContractClient
    Inherits DuplexClientBase(Of IMyContract)

    Public Sub New(ByVal callbackinstance As Object, ByVal binding As Binding, ByVal remoteAddress As EndpointAddress)
        MyBase.New(callbackinstance, binding, remoteAddress)
    End Sub
End Class

Public Class MyCallbackClient
    Implements IMyContractCallback

    Public Sub OnCallBack() Implements IMyContractCallback.OnCallBack
        Console.WriteLine("Hi from client!")
    End Sub
End Class


Module Module1

    Sub Main()
        Dim uri As New Uri("net.tcp://localhost")
        Dim binding As New NetTcpBinding()
        Dim host As New ServiceHost(GetType(Myservice), uri)
        host.AddServiceEndpoint(GetType(IMyContract), binding, "")
        host.Open()

        Dim callback As New MyCallbackClient()
        Dim client As New MyContractClient(callback, binding, New EndpointAddress(uri))
        Dim proxy As IMyContract = client.ChannelFactory.CreateChannel()

        proxy.DoSomething()
        ' Printed in console:
        '  Hi from server!
        '  Hi from client!

        Console.ReadLine()

        client.Close()
        host.Close()
    End Sub

End Module
2

If I'm reading your question right, you want to have a two-way conversation between the client and the server (the server can communicate back to the client). The WSDualHttpBinding gives you this functionality.

The unfortunate reality with WCF is that there is no such thing as a simple example. It requires you to define contracts, configure the services, and use a host, and create client code. Take a look at this article for a somewhat simple example.

Michael Meadows
  • 27,796
  • 4
  • 47
  • 63