Question

I'm trying to get to grips with WCF, in particular writing a WCF Service application with callback.

I've setup the service, together with the callback contract but when the callback is called, the app is timing out.

Essentially, from a client I'm setting a property within the service class. The Setter of this property, if it fails validation fires a callback and, well, this is timing out.

I realise that this is probably to it not being an Asynchronous calback, but can someone please show me how to resolve this?

Thanks

  // The call back (client-side) interface
public interface ISAPUploadServiceReply
{
    [OperationContract(IsOneWay = true)]
    void Reply(int stateCode);
}

// The Upload Service interface
[ServiceContract(CallbackContract = typeof(ISAPUploadServiceReply))]
public interface ISAPUploadService
{

    int ServerState
    {
        [OperationContract]
        get;
        [OperationContract(IsOneWay=true)]
        set;

And the implementation...

public int ServerState
    {
        get 
        { 
            return serverState; 
        }
        set 
        {
            if (InvalidState(Value))
            {
               var to = OperationContext.Current.GetCallbackChannel<ISAPUploadServiceReply>();
               to.Reply(eInvalidState);
            }
            else serverState = value; 
        } 
    }

My interfaces have been modified to (hopefully) reflect an asynchronous ability

  // The call back (client-side) interface
public interface ISAPUploadServiceReply
{
   [OperationContractAttribute(AsyncPattern = true)]
    IAsyncResult BeginReply(string message, AsyncCallback callback, object state);
    void EndReply(IAsyncResult result);
}

..and the implementation (please, I'm very, very, guessing on this - and besides it doesn't work - 'server replied with runtime error of unknown response ....'

 public class SAPUploadServiceClient : ISAPUploadServiceReply
{
    private string msg;

    public IAsyncResult BeginReply(string message, AsyncCallback callback, object state)
    {
       // Create a task to do the work
       msg = message;
      var task = Task<int>.Factory.StartNew(this.DisplayMessage, state);
      return task.ContinueWith(res => callback(task));

    }

    public void EndReply(IAsyncResult result)
    {
      MessageBox.Show(String.Format("EndReply"));
    }

    private int DisplayMessage(object state)
    {
       MessageBox.Show(String.Format("Display Message At last here's  the message : {0}", msg));
       return 1;
    }
}

The callback is invoked by a public method within my service, callable from a client

  public void FireCallback(string msg)
    {
        ISAPUploadServiceReply callback = OperationContext.Current.GetCallbackChannel<ISAPUploadServiceReply>();

        callback.BeginReply("Hello from service " + msg, callback.EndReply, null);
    }

The interface modification is ...

[ServiceContract(CallbackContract = typeof(ISAPUploadServiceReply))]
public interface ISAPUploadService
{
    [OperationContract(IsOneWay = true)]
    void FireCallback(string msg);

Please- I know the above looks quite desperate and that's why it is. I just want to get ANY call back working from my WCF Service so I can progress with this. It shouldn't be this hard to simply invoke an asynchronous callback.

I simply want to fire an event to the client from the service. That is ALL I'm trying to do. The following perhaps explains the process of events that I'm trying to achieve more clearly...

Client calls service method and waits.... Service method 1 undertakes some work (in this case, querying a database and constructing an xml response) When the work is finished, the service fires a callback event telling the client the work has completed and an XML response is available. Client reads XML response and continues.

Sheesh...

Was it helpful?

Solution

I am not 100% sure, but I remember I had such issues when I called the callback method from the same thread.. This should solve it:

public int ServerState
    {
        get
        {
            return serverState;
        }
        set
        {
            if (InvalidState(Value))
            {
                var to = OperationContext.Current.GetCallbackChannel<ISAPUploadServiceReply>();
                Task.Factory.StartNew(() =>
                    {
                        to.Reply(eInvalidState);
                    });

            }
            else
                serverState = value;
        }
    }

OTHER TIPS

Server side:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service1 : IService1 { ... }

Executing callback (service):

var to = OperationContext.Current.GetCallbackChannel<IChatServiceCallback>();
Task.Factory.StartNew(() =>
{
    to.myCallbackFunction( ... );
});

Client side callback:

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
public class MyServiceCallback : IService1Callback { ... }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top