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

发布于 2024-12-11 20:07:52 字数 1530 浏览 0 评论 0原文

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

  1. 操作内服务的请求回复操作和进度消息的单向回调方法?

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

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

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

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

但我不确定 WCF 为我提供了多少开箱即用的服务。


换句话说,我想做一些类似于下面的代码(psuedo)的事情。它的工作。您认为这种方法有什么问题吗? (这个想法是在阻塞调用中调用回调方法。服务在多种并发模式下运行。所以我声明回调 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 线程有意义吗?

My contract has request-reply operation which performs multiple tasks. So I would like to inform about the progress of the operation to the client as its a long running operation. So Duplex is the ideal choice as I can use call back methods. But my operation returns results at the end of the operations. So what is the recommendation to solve this problem?

  1. Reuest-reply operation and one-way call back method for the progress messaages from the service within the operation?

  2. Blocking (request-reply) operation and blocking (sync) progress messages from service

  3. Will the call back method uses same channel, so will my blocking (request-reply) method assumes its its result?

    • If yes, should I perform my service operation asynchronously.
  4. Will the call back method will come in another worker thread or will be returned to the same thread which has given the instance context?

I think blocking service operation and blocking call back method for progress message (if it can return on another thread) will be ideal and easy solution.

But I am not sure how much WCF provides me out of box.


In Other words I want to do something similar to the below code(psuedo). Its working. Do you see any issues with this approach? (The idea is to calling a callback method within a blocking call. Service runs in multiple concurencymode. So i declared callback UseSynchronizationContext = false) to avoid deadlock.any issues are there with the below approach?

[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();
           ...
               ...
     }
}    

Eventhough if i set it UseSynchronizationContext to true, WCF is invoking the report method in worker thread itself. So looks like I dont need to set it to false. Will it make sense only for UI thread becasue I am invoking operation already in a another thread?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

以为你会在 2024-12-18 20:07:52
[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);
    }
}
[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));
        }

    }
}

//Client would look something like this...

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);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文