Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make wcf client wait for the callback

Tags:

c#

wcf

I'm currently working on a project, where I have to manage an application via a wcf client. The problem I'm facing is that after making a call to the server I need the client to wait for the callback to be made. Here is the scenario:

I make a call to the service which shows a window and then the server app is idle. When i click a button on the window, it makes a callback to the client. during the time, the client UI has to be disabled - it has to wait for the callback. Could you please tell me how I can achieve this? Does it have something to do with Concurrency Mode or the Operation Contract attribute?

This is my code for the ServiceContract and the CallbackContract:

[ServiceContract(CallbackContract = typeof(IWCFServiceCallback))]
public interface IWCFService
{
    [OperationContract]
    void OpenWindow();
}
public interface IWCFServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void ReturnValue(object[] value);
}
like image 848
Bartek Avatar asked Mar 01 '17 07:03

Bartek


3 Answers

No, the feature you describe has nothing to do with Concurrency Mode or the Operation Contract. You probably need to implement the feature using semaphores (Mutex, Monitor, whatever ...) and callbacks from server to client to set the semaphore.

Having said that the functionality you describe seems really odd.

like image 181
Ignacio Soler Garcia Avatar answered Nov 15 '22 17:11

Ignacio Soler Garcia


You can do this by implementing an asynchronous service operation and calling it using Async/Await.

Disable your client UI just before calling your service, and then enable it after the callback returns.

https://msdn.microsoft.com/en-us/library/ms731177.aspx

using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace Microsoft.WCF.Documentation
{
  [ServiceContractAttribute(Namespace="http://microsoft.wcf.documentation")]
  public interface ISampleService{

    [OperationContractAttribute]
    string SampleMethod(string msg);

    [OperationContractAttribute(AsyncPattern = true)]
    IAsyncResult BeginSampleMethod(string msg, AsyncCallback callback, object asyncState);

    //Note: There is no OperationContractAttribute for the end method.
    string EndSampleMethod(IAsyncResult result);

    [OperationContractAttribute(AsyncPattern=true)]
    IAsyncResult BeginServiceAsyncMethod(string msg, AsyncCallback callback, object asyncState);

    // Note: There is no OperationContractAttribute for the end method.
    string EndServiceAsyncMethod(IAsyncResult result);
  }

  public class SampleService : ISampleService
  {
    #region ISampleService Members

    public string  SampleMethod(string msg)
    {
      Console.WriteLine("Called synchronous sample method with \"{0}\"", msg);
      return "The sychronous service greets you: " + msg;
    }

    // This asynchronously implemented operation is never called because 
    // there is a synchronous version of the same method.
    public IAsyncResult BeginSampleMethod(string msg, AsyncCallback callback, object asyncState)
    {
      Console.WriteLine("BeginSampleMethod called with: " + msg);
      return new CompletedAsyncResult<string>(msg);
    }

    public string EndSampleMethod(IAsyncResult r)
    {
      CompletedAsyncResult<string> result = r as CompletedAsyncResult<string>;
      Console.WriteLine("EndSampleMethod called with: " + result.Data);
      return result.Data;
    }

    public IAsyncResult BeginServiceAsyncMethod(string msg, AsyncCallback callback, object asyncState) 
    {
      Console.WriteLine("BeginServiceAsyncMethod called with: \"{0}\"", msg);
      return new CompletedAsyncResult<string>(msg);
    }

    public string EndServiceAsyncMethod(IAsyncResult r)
    {
      CompletedAsyncResult<string> result = r as CompletedAsyncResult<string>;
      Console.WriteLine("EndServiceAsyncMethod called with: \"{0}\"", result.Data);
      return result.Data;
    }
    #endregion
  }

  // Simple async result implementation.
  class CompletedAsyncResult<T> : IAsyncResult
  {
    T data;

    public CompletedAsyncResult(T data)
    { this.data = data; }

    public T Data
    { get { return data; } }

    #region IAsyncResult Members
    public object AsyncState
    { get { return (object)data; } }

    public WaitHandle AsyncWaitHandle
    { get { throw new Exception("The method or operation is not implemented."); } }

    public bool CompletedSynchronously
    { get { return true; } }

    public bool IsCompleted
    { get { return true; } }
    #endregion
  }
}
like image 30
InteXX Avatar answered Nov 15 '22 16:11

InteXX


When the concurrenymode is ConcurrencyMode.Single and the client calls the service, the service will create a lock. When it calls the callback interface with IsOneWay is false a result message will be sent back to the service. The service will create the lock again and will deadlock because the lock is held from the client call still. With ConsurrencyMode. Reentrant the lock will sneakily be released when calling back and reacquired on return so you could use that. IsOneWay=true is also a solution as no result message is sent back the service calling back.

So you should be able to lock you GUI just before calling the service and unlock it in the callback when the callback operation has IsOneWay = true or the service has ConcurrencyMode.Reentrant configured

like image 1
Serve Laurijssen Avatar answered Nov 15 '22 17:11

Serve Laurijssen