简体   繁体   中英

Make wcf client wait for the callback

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);
}

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.

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
  }
}

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

Thanks for your answers. I solved the problem by using the Win32 ShowWindow function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM