WCF - 告知客户端的进度(我可以在请求/回复操作中使用单向回调方法)

时间:2011-10-23 10:17:13

标签: wcf wcf-client

我的合同有执行多项任务的请求 - 回复操作。所以我想告诉客户操作的进度,因为它是一个长期运行的操作。所以Duplex是理想的选择,因为我可以使用回调方法。但是我的操作在操作结束时返回结果。那么解决这个问题的建议是什么?

  1. 操作中服务进度消息的Reuest-reply操作和单向回调方法?

  2. 阻止(请求 - 回复)操作和阻止(同步)来自服务的进度消息

  3. 回调方法是否会使用相同的通道,我的阻塞(请求 - 回复)方法会假设其结果吗?

    • 如果是,我应该异步执行我的服务操作。
  4. 回调方法是否会出现在另一个工作线程中,还是会返回到给出实例上下文的同一个线程?

  5. 我认为阻止服务操作和阻止进程消息的回调方法(如果它可以在另一个线程上返回)将是理想且简单的解决方案。

    但我不确定WCF能为我提供多少开箱即用。


    换句话说,我想做类似下面的代码(psuedo)。它的工作。你觉得这种方法有什么问题吗? (我的想法是在阻塞调用中调用一个回调方法。服务在多个concurencymode中运行。所以我声明了回调UseSynchronizationContext = false)以避免死锁。以下方法有哪些问题?

    [ServiceContract(CallbackContract(typeof(IServiceCallback)]]
    public interfact IService
    {
         //A long (timetaken) request-reply operation
         string LonggggWork();
    }
    
    public interface IServiceCallback
    {
         void Report(string msg);
    }
    
    [CallbackBehavior(ConcuerencyMode.Multiple, UseSynchronizationContext=false)]
    public ClientCallback : IServiceCallback
    {
    public void Report(string msg)
    {
         Console.WriteLine(msg);
    }
    }
    [ServiceBehavior(ConcurencyMode.Multiple, InstanceMode.PerSession)]
    publci Service : IService
    {
         IServiceCallback callback = ....;
         public string LongggWork()
         {
              callback.Report("task1");
              task1();
              callback.Report("task2");
              task2();
               ...
                   ...
         }
    }    
    

    尽管我将UseSynchronizationContext设置为true,但是WCF正在工作线程本身中调用报表方法。所以看起来我不需要将其设置为false。它只对UI线程有意义,因为我在另一个线程中调用了操作吗?

1 个答案:

答案 0 :(得分:1)

[ServiceContract(CallbackContract = typeof(ISubscriber))]
public interface IJobProcessor
{
    [OperationContract(IsOneWay = true)]
    void ProcessJob();
}



[ServiceContract]
public interface ISubscriber
{
    //This would be the operation using which the server would notify the client about the status.
    [OperationContract]
    void UpdateStatus(string statusMessage);
}

class Program
{
    static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(JobProcessor), new Uri[] { new Uri("net.tcp://localhost:10000") });
        host.AddServiceEndpoint(typeof(IJobProcessor), new NetTcpBinding(), "jobprocessor");
        host.Open();
        Console.WriteLine("Server  running. Press enter to quit!");
        Console.Read();
    }
}

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
public class JobProcessor : IJobProcessor
{
    public void ProcessJob()
    {
        ISubscriber subscriber = OperationContext.Current.GetCallbackChannel<ISubscriber>();
        for (int i = 0; i < 5; i++)
        {
            Thread.Sleep(1000 * 10);
            subscriber.UpdateStatus(String.Format("{0} % complete", (i + 1) * 20));
        }

    }
}

//客户端看起来像这样......

class Program
{
    static void Main(string[] args)
    {
        var proxy = DuplexChannelFactory<IJobProcessor>.CreateChannel(new InstanceContext(new Subscriber()), new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:10000/jobprocessor"));
        proxy.ProcessJob();
        Console.Write("Client proceeding with other work...");
        Console.Read();
    }
}

public class Subscriber : ISubscriber
{
    public void UpdateStatus(string statusMessage)
    {
        Console.WriteLine(statusMessage);
    }
}