【问题标题】:WCF Duplex Callback in WPF Application: Dispatcher.BeginInvoke doesn't execute the delegateWPF 应用程序中的 WCF 双工回调:Dispatcher.BeginInvoke 不执行委托
【发布时间】:2012-07-20 14:42:34
【问题描述】:

我正在尝试设置一个简单的双工服务,让客户端连接到服务器。任何连接的客户端都可以执行BookAdded 服务操作。发生这种情况时,服务器应该在所有连接的客户端上引发回调,以通知它们更改。

回调似乎工作正常,只是回调操作需要使用Dispatcher.BeginInvoke 在 UI 线程上运行某些东西。

在我的情况下,Console.WriteLine("Callback thread") 被执行购买 Console.WriteLine("Dispatcher thread") 没有。这是什么原因?

我的服务合同:

public interface ICallback
{
    [OperationContract(IsOneWay = true)]
    void BookAdded(string bookId);
}

[ServiceContract(
    CallbackContract = typeof(ICallback), 
    SessionMode = SessionMode.Required)]
public interface IService
{
    [OperationContract]
    bool BookAdded(string bookId);
}

我的服务实现:

[ServiceBehavior(
    UseSynchronizationContext = false,
    InstanceContextMode = InstanceContextMode.PerSession, 
    ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MyService : IService
{
    public bool BookAdded(string bookId)
    {
        try
        {
            Console.WriteLine("Client Added Book " + bookId);

            foreach (ICallback callback in connectedClients)
            {
                callback.BookAdded(bookId);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        return true;
    }
}

我的客户端实现:

[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyCallBack: ICallback, IDisposable
{
    private Dispatcher theDispatcher;
    private InstanceContext context;
    private WcfDuplexProxy<IService> proxy;

    [ImportingConstructor]
    public MyCallBack()
    {  
        theDispatcher = Dispatcher.CurrentDispatcher;
        context = new InstanceContext(this);
        proxy = new WcfDuplexProxy<IService>(context);

        proxy.Connect();
    }

    public IService Service
    {
        get
        {
            return proxy.ServiceChannel;
        }
    }

    public void CallServiceOperation()
    {
        Service.BookAdded("BOOK1234");
    }

    public void BookAdded(string bookId)
    {
        Console.WriteLine("Callback thread");
        theDispatcher.BeginInvoke(new Action(() => { Console.WriteLine("Dispatcher thread"); }));
    }

    public void Dispose()
    {
        Service.Disconnect();
        proxy.Close();
    }

【问题讨论】:

    标签: c# wcf dispatcher wcf-callbacks


    【解决方案1】:

    我怀疑正在发生的事情是 UI 线程仍然被阻塞在对服务器的原始调用尚未完成。 我认为,如果您将 client 上的并发模式更改为可重入,它可能会起作用。 罢工>。您需要做的是在回调上设置 [CallbackBehavior(UseSynchronizationContext = false)]。

    This article 很好地解释了这个问题。

    GJ

    【讨论】:

    • 我的代码实际上是基于那篇文章。我现在把情况简化回原来的文章: [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)] [CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Single)] 问题依旧。即使 UI 线程被锁定,Dispatcher.BeginInvoke 也不会将委托排队,并且一旦 UI 线程可用,它就会运行? UI 线程没有死锁,因为 UI 继续正常工作。
    • (对不起,没有很好地阅读示例)如果您将 Console.Writeline 包装在它自己的方法中并使用操作调用它会发生什么?在那里设置一个断点。这样,您可以查看它是否在调用方法或写入控制台时失败。还将 VS 设置为在 CLR 异常上中断,以便它停止。
    • 断点没有被命中,似乎也没有抛出任何 CLR 异常。
    • 好的,这样可以将其缩小到 Dispatcher.BeginInvoke... 如果您将其更改为 Dispatcher.CurrentDispatcher.BeginInvoke 会怎样?或在单独的行上创建操作然后调用它?只是为了进一步缩小范围。
    • 这也没什么区别!这真的很奇怪。
    【解决方案2】:

    我想我遇到过与您类似的问题。我用一个新线程来解决它来调用 Dispatcher.beginInvoke。据我了解,UI线程向Service发送请求,Service将在服务操作期间调用在您的客户端中实现的回调合约。因此,如果在回调操作中,它会调用 UI 线程的控制,该线程等待服务操作的响应。这就是客户端死锁的原因。所以你可以试试下面的代码:Thread th=new Thread(new ThreadStart(()=>{Console.WriteLine("Callback thread");
    theDispatcher.BeginInvoke(new Action(() => { Console.WriteLine("Dispatcher thread"); }));
    })); th.Start();

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      • 2017-01-20
      • 1970-01-01
      • 2014-08-10
      相关资源
      最近更新 更多