C# WPF应用程序中的WCF双工回调:Dispatcher.BeginInvoke不';不要执行委托

C# WPF应用程序中的WCF双工回调:Dispatcher.BeginInvoke不';不要执行委托,c#,wcf,dispatcher,wcf-callbacks,C#,Wcf,Dispatcher,Wcf Callbacks,我正在尝试设置一个简单的双工服务,客户机通过该服务连接到服务器。任何连接的客户端都可以执行BookAdded服务操作。当这种情况发生时,服务器应该对所有连接的客户机发出回调,以通知他们更改 回调似乎工作正常,只是回调操作需要使用Dispatcher.BeginInvoke在UI线程上运行一些东西 在我的例子中,Console.WriteLine(“回调线程”)执行,而Console.WriteLine(“调度线程”)不执行。这是什么原因 我的服务合同: public interface ICal

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

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

在我的例子中,
Console.WriteLine(“回调线程”)
执行,而
Console.WriteLine(“调度线程”)
不执行。这是什么原因

我的服务合同:

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();
    }
我的客户端实现:

[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();
    }
[CallbackBehavior(UseSynchronizationContext=false,ConcurrencyMode=ConcurrencyMode.Multiple)]
公共类MyCallBack:ICallback,IDisposable
{
私人调度员;
私有InstanceContext上下文;
专用WcfDuplexProxy代理;
[导入构造函数]
公共MyCallBack()
{  
Dispatcher=Dispatcher.CurrentDispatcher;
上下文=新的InstanceContext(此);
proxy=新的WcfDuplexProxy(上下文);
proxy.Connect();
}
公共色情服务
{
得到
{
返回proxy.ServiceChannel;
}
}
public void CallServiceOperation()
{
服务。新增簿册(“簿册1234”);
}
已添加公共作废bookId(字符串bookId)
{
Console.WriteLine(“回调线程”);
Dispatcher.BeginInvoke(新操作(()=>{Console.WriteLine(“Dispatcher线程”);});
}
公共空间处置()
{
Service.Disconnect();
proxy.Close();
}

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

很好地解释了这个问题


GJ

我想我在你的问题上也遇到过类似的问题。我用一个新线程来调用Dispatcher.beginInvoke解决了这个问题。据我所知,UI线程向服务发送请求,服务将在服务操作期间调用在客户端实现的回调约定。因此,如果在回调操作中调用UI thre的控件等待服务操作响应的ad。这就是客户端死锁的原因。因此您可以尝试下面的代码:
Thread th=new Thread(new ThreadStart(()=>{Console.WriteLine(“回调线程”);
Dispatcher.BeginInvoke(新操作(()=>{Console.WriteLine(“Dispatcher线程”);}));

}));th.Start();

我实际上是根据那篇文章编写代码的。我现在将情况简化为原始文章:[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?或者在单独的行上创建操作,然后调用它?只是为了进一步缩小范围。这也没什么区别!这真的很奇怪。